Scenario
Consider the following vue component:
<template>
<div>
<slot>{{ title }}</slot>
<ul>
<li v-for="label in labels" :key="label">
<input
type="checkbox"
v-model="checked"
:label="label"
:id="label"
:value="label"
/>
<label :for="label">{{ label }}</label>
</li>
</ul>
</div>
</template>
<script>
import Component from "vue-class-component";
import Vue from "vue";
@Component({
props: {
labels: {
type: Array,
},
title: {
type: String,
},
},
watch: {
checked: [
{
handler: "updateParent",
},
],
},
})
export default class CheckboxList extends Vue {
checked = [];
updateParent() {
this.$emit("update", this.checked);
}
}
</script>
This component will display a list of checkboxes based on the labels
prop passed down from the parent.
When both components are included on the same page, with a toggle using v-if
like so:
<template>
<div id="app">
<img alt="Vue logo" src="./assets/logo.png" width="10%" />
<hr />
<button type="button" @click="state = 'numbers'">
Show number checklist
</button>
<button type="button" @click="state = 'letters'">
Show letter checklist
</button>
<CheckboxList
v-if="state === 'numbers'"
title="numbers"
:labels="numbers"
@update="checkedNumbers = $event"
></CheckboxList>
<CheckboxList
v-if="state === 'letters'"
title="letters"
:labels="letters"
@update="checkedLetters = $event"
></CheckboxList>
<div>
<span>Checked letters:</span> {{ checkedLetters }}
<span>Checked numbers:</span> {{ checkedNumbers }}
</div>
</div>
</template>
<script>
import Vue from "vue";
import HelloWorld from "./components/HelloWorld";
import CheckboxList from "./CheckboxList.vue";
import Component from "vue-class-component";
@Component({
components: {
CheckboxList,
},
})
export default class App extends Vue {
numbers = [1, 2, 3, 4, 5];
letters = ["a", "b", "c", "d"];
state = "numbers";
checkedLetters = [];
checkedNumbers = [];</pre>
The above setup will result in the demonstrated UI:
https://i.sstatic.net/HabXM.png
Why does toggling between the two components (with v-if
) and checking the boxes lead to mixed-up data, as seen in this behavior?
https://i.sstatic.net/x9DOA.gif
A functional example is available here: https://codesandbox.io/s/epic-resonance-plwvi?file=/src/App.vue