DEV Community

Danilo Miranda
Danilo Miranda

Posted on

Vue two way data-binding in custom checkbox

When writing vue application, you'll probably come across a situation where you need to write custom input components, and therefore leverage the two way data binding functionality.

A simple custom text input is easiy achievable and it's documented here

But there's a different approach to achieve the same two way data binding functionality in custom checkbox components.

Creating the custom checkbox component

Let's start creating our component. It will be as simple as just rendering the checkbox and a label can be set through props.

Checkbox.vue

<template>
    <label>
        <input  type="checkbox" :value="inputValue"  v-model="model" />
        <span>{{ label }}</span>
    </label>
</template>

<script>
export default {
  name: "Checkbox",
  props: {
    label: String,
    value: Array,
    inputValue: String,
  },
  computed: {
    model: {
      get() {
        return this.value;
      },
      set(value) {
        this.$emit("input", value);
      },
    },
  },
};
</script>
Enter fullscreen mode Exit fullscreen mode

Now, take a look at this part:

<input  type="checkbox" :value="inputValue"  v-model="model" />
Enter fullscreen mode Exit fullscreen mode

We are defining a checkbox input, and binding the value attribute to our inputValue, which will simply be used to determine the input's value for a form submission for example, just like you would do with normal html

<input  type="checkbox" value="somoething" />
Enter fullscreen mode Exit fullscreen mode

Now, v-model is bound to a property called model which is a computed property:

computed: {
    model: {
      get() {
        return this.value;
      },
      set(value) {
        this.$emit("input", value);
      },
    },
  },
Enter fullscreen mode Exit fullscreen mode

The getter for this property will simply return value to v-model and when the data has to be updated, through the setter, we emit the input event, to let the part of the application that's using this custom checkbox component, that the value has been updated.

It's important to note that the value property was declared as being an array, since each time we mark a new checkbox, this checkbox value will be pushed to this array bound to v-model property.

Using the component

Now that we have defined how our component will work, we can use it in an example and see if it wil work.

I'll just define a simple Vue component that will use this checkbox component we just created:

Home.vue

<template>
  <div>
    <Checkbox label="React" inputValue="react" v-model="selectedOptions" />
    <Checkbox label="Vue" inputValue="vue" v-model="selectedOptions" />
    <Checkbox label="Angular" inputValue="angular" v-model="selectedOptions" />

    <br /><br /><br />

    <ul>
      <li v-for="(option, index) of selectedOptions" :key="index">
        {{ option }}
      </li>
    </ul>
  </div>
</template>

<script>
import Checkbox from "./Checkbox";

export default {
  name: "Home",
  props: {},
  components: {
    Checkbox,
  },
  data() {
    return {
      selectedOptions: [],
    };
  },
};
</script>
Enter fullscreen mode Exit fullscreen mode

In this example, we have three checkboxes component in use, with three different value for each one of them: react, vue and angular with their respective labels.

    <Checkbox label="React" inputValue="react" v-model="selectedOptions" />
    <Checkbox label="Vue" inputValue="vue" v-model="selectedOptions" />
    <Checkbox label="Angular" inputValue="angular" v-model="selectedOptions" />
Enter fullscreen mode Exit fullscreen mode

We are binding the v-model property to selectedOptions reactive data property of our home component, which wil be an array.

To make sure that we are updating this selectedOptions each time a check or uncheck an input, I added a simple loop, to render each value in selectedOptions array:

<ul>
    <li v-for="(option, index) of selectedOptions" :key="index">
        {{ option }}
    </li>
</ul>
Enter fullscreen mode Exit fullscreen mode

Nothing selected:
Nothing selected

All selected:
All selected

Two selected:
Two selected

You can see a working example here in CodeSandbox:

Edit dreamy-sea-0467f

Discussion (0)