9👍
Take a look what v-model
on custom components does
<mycomponent v-model="data" />
is same as
<mycomponent
v-bind:value="data"
v-on:input="data= $event" />
So if you do $emit("input", $event.target.value)
inside of your component, whatever $event.target.value
is, it replaces your model. But you need an "input" event so the v-model
on your component works. value
emitted just has to be in the same format as a model you are receiving.
On top of that whats the point of having a model and at the same time support entries.active
? It’s clear duplicity. Passed model should be only thing that decides whether checkbox is checked or not….
Do it like this:
Vue.component("checkbox-group", {
props: {
name: String,
alignment: String,
block: Boolean,
entries: Array,
errors: Array,
value: Array
},
computed: {
model: {
get() { return this.value },
set(newValue) { this.$emit('input', newValue)}
}
},
template: `
<div class="field">
<p class="help is-danger" v-for="message in errors" :key="message">
{message}
</p>
<div class="control" :class="'has-text-' + alignment">
<template v-for="entry in entries">
<label class="checkbox" :key="entry.value">
<input
type="checkbox"
:name="name"
:value="entry.value"
v-model="model"
/>
{{ entry.label }}
</label>
<br v-if="block" :key="'br_'+entry.value"/>
</template>
</div>
</div>
`
});
Changes:
- added
value
prop – its set by Vue to a value insidev-model
attribute of your component - instead of binding
:checked
and@change
on eachinput
, we usev-model
instead as it handles all the array slicing/pushing (model is an array) - But because our model (
value
prop) is from prop, we cannot us it directly inv-model
(child cannot update prop from parent). In this kind of situations the computed with setter are very useful.- when the computed is read, we return value of
value
prop - when the computed is set (by
v-model
used oninput
), we just$emit
the value to the parent - Parent will update its property used in
v-model
and our child component receives the new value via avalue
prop
- when the computed is read, we return value of
Update
As this my old answer still receives upvotes I have decided to update it. Previous version was working but had one little quirk – component was not reactive to potential value
prop changes from the parent . This new version is simply better – works in all cases and is less code…
Bonus – Vue 3 version
Vue.component("checkbox-group", {
props: {
name: String,
alignment: String,
block: Boolean,
entries: Array,
errors: Array,
modelValue: Array
},
emits: ['update:modelValue'],
computed: {
model: {
get() { return this.modelValue },
set(newValue) { this.$emit('update:modelValue', newValue)}
}
},
template: `
<div class="field">
<p class="help is-danger" v-for="message in errors" :key="message">
{message}
</p>
<div class="control" :class="'has-text-' + alignment">
<template v-for="entry in entries" :key="entry.value">
<label class="checkbox">
<input
type="checkbox"
:name="name"
:value="entry.value"
v-model="model"
/>
{{ entry.label }}
</label>
<br v-if="block" />
</template>
</div>
</div>
`
});
0👍
Repeat the checkboxes as necessary, using v-model with the same name, different values.
Such as this HTML:
<form>
<input type="checkbox" id="support_1" value="1" v-model="support">
<label for="support_1">Restart the app</label>
<input type="checkbox" id="support_2" value="2" v-model="support">
<label for="support_2">Log off and on</label>
</form>
<p>
{{ support }}
</p>
And the code:
data() {
return {
support: [],
}
},