Vue: v-model with custom element that wrap checkbox.

Created on 3 Oct 2016  路  10Comments  路  Source: vuejs/vue

Hi,

I am using vuejs 2.0.1 and I want to create a component that looks like this:

    <vue-checkbox v-model="page.ads_able"></vue-checkbox>

As from the api page that v-model is a syntactic sugar combinding :value and @input.

So I write a template with a props name value and a method for input event like this:

...
<input type="checkbox" :value="value" @input="onInput" />
...
...
props: {
        value: {},
},
methods: {
        onInput(event) {
            this.$emit('input', event.target.value)
        }
}
...

But it doesn't work. I don't know if there any special care about checked attribute of the checkbox. I tried the exact same thing with <select> and it's worked as aspect though. Any suggestion?

Most helpful comment

Well, I think I find a solution to my own question.

I need to set a data variable to accept value from props and change that data at the corresponding event then emit the input event so that v-model can handle the value change. Something along these lines:

template

<input type="checkbox" 
           value="1"
           :checked="checked"
           @change="change"
    />

And in javascript:

      data: function() {
            return {
                checked: this.value
            };
        },
        props: ['value'],

       methods: {
            change: function() {
                this.checked = !this.checked;
                this.$emit('input', this.checked);
            }
       }

That's work now. :D

All 10 comments

Well, I think I find a solution to my own question.

I need to set a data variable to accept value from props and change that data at the corresponding event then emit the input event so that v-model can handle the value change. Something along these lines:

template

<input type="checkbox" 
           value="1"
           :checked="checked"
           @change="change"
    />

And in javascript:

      data: function() {
            return {
                checked: this.value
            };
        },
        props: ['value'],

       methods: {
            change: function() {
                this.checked = !this.checked;
                this.$emit('input', this.checked);
            }
       }

That's work now. :D

@phatchai Here is a work around for the issue.
https://jsfiddle.net/cv2tL9oy/

Issues are for bugs and feature requests only. Please use forum.vuejs.org or Gitter.

@phatchai Your example works not correctly. When we change parent model - yours checkbox component wouldn't change.
We need to take checked from props and emit event 'input' onChange, and don't store local state.

Here is my example:

<template>
    <input type="checkbox" :checked="value" @change="changeHandler">
</template>

<script>
export default {
    name: 'v-switch',
    props: ['value'],
    methods: {
        changeHandler () {
            this.$emit('input', !this.value)
        }
    }
}
</script>

There needs to be better documentation on v-model. Everywhere I look says it's just a shorthand for :input="$emit('input', event.target.value)" but this issue proves otherwise. The bug here is lack of documentation.

Don't use any of the other examples here! They are broken!
Here's the solution: use $event.target.checked, not $event.target.value!

@myxibrium solution didn't work to me but this did (changing :value for :checked):

<template>
    <input type="checkbox" :checked="value" @input="$emit('input', $event.target.checked)" />
</template>

<script>
export default {
    props: ['value']
};
</script>

I can also bind a group of checkboxes to an array. The array will then contain a list of the values of the checked checkboxes, see 2nd example in the documentation https://vuejs.org/v2/guide/forms.html#Checkbox
How to wrap a checkbox _correctly_ so that this behavior will also be preserved?

I can also bind a group of checkboxes to an array. The array will then contain a list of the values of the checked checkboxes, see 2nd example in the documentation https://vuejs.org/v2/guide/forms.html#Checkbox
How to wrap a checkbox _correctly_ so that this behavior will also be preserved?

https://vuejs.org/v2/api/#model

Use a custom model prop and event. Eg.
model: { prop: 'modelValue', event: 'change' }
Bind the @change to the checkbox and $emit the value differently based on whether the v-model value (this.modelValue) is an array (multiple checkboxes) or not (single checkbox).

@vincesp I managed to solve this by using @rjoo 's answer and a bit of array checking when the box change.

methods: {
    change() {
      const checked = this.checked.slice();
      const found = checked.indexOf(this.value);
      if (found !== -1) {
        checked.splice(found, 1);
      } else {
        checked.push(this.value);
      }
      this.$emit("change", checked);
    }
  }
};

codesandbox here: https://codesandbox.io/s/5x0296z7jp

I didn't put handling of single select boxes in there, but that's fairly trivial to do. Hope it helps.

Sorry for beign late. I came up with this solution, what do you guys think?

Vue.component("v-check", {
  template: `   
  <input type="checkbox" :value="value" v-model="proxyChecked" />
  `,
  model: {
    prop: "checked",
    event: "change",
  },
  props: {
    checked: {
      type: [Array, Boolean],
      default: false,
    },
    value: {
      default: null,
    },
  },
  computed: {
    proxyChecked: {
      get() {
        return this.checked;
      },
      set(val) {
        this.$emit("change", val);
      },
    },
  },
});

Code demo here: https://jsfiddle.net/ariel0196/euzn79gc/3/

Was this page helpful?
0 / 5 - 0 ratings

Related issues

bdedardel picture bdedardel  路  3Comments

bfis picture bfis  路  3Comments

paceband picture paceband  路  3Comments

aviggngyv picture aviggngyv  路  3Comments

loki0609 picture loki0609  路  3Comments