Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

v-model with custom element that wrap checkbox. #3838

Closed
phattarachai opened this issue Oct 3, 2016 · 12 comments
Closed

v-model with custom element that wrap checkbox. #3838

phattarachai opened this issue Oct 3, 2016 · 12 comments

Comments

@phattarachai
Copy link

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?

@phattarachai
Copy link
Author

phattarachai commented Oct 3, 2016

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

@anishdcruz
Copy link

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

@LinusBorg
Copy link
Member

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

@OperKH
Copy link

OperKH commented Dec 11, 2017

@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>

@myxibrium
Copy link

myxibrium commented Sep 14, 2018

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!

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

@gonzaloserrano
Copy link

@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>

@vincesp
Copy link

vincesp commented Oct 22, 2018

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?

@rjoo
Copy link

rjoo commented Nov 27, 2018

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).

@ortonomy
Copy link

ortonomy commented Feb 12, 2019

@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.

@arvx47
Copy link

arvx47 commented Jun 10, 2020

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/

@m4heshd
Copy link

m4heshd commented Jun 20, 2021

Don't know about Vue 2 but for Vue 3, it's as simple as this.

props: {
    modelValue: [Boolean, Array]
}
<input
    type="checkbox"
    v-model="modelValue"
    @change="$emit('update:modelValue', modelValue)"
>

@cjbeattie
Copy link

Not sure if things have changed since the above was written, but none of the above worked for me.
The Vue docs talk about the need for emits: https://vuejs.org/guide/components/events.html#usage-with-v-model
So I added it in, and it works. I tweaked their example a bit so that it works for checkbox:

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

<script>
  export default {
    props: ['modelValue'],
    emits: ['update:modelValue']
  }
</script>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests