I am stuck at making a CheckBoxGroup with a prop array as v-model. I have read the vuejs guide: https://v2.vuejs.org/v2/guide/forms.html#Checkbox which has the v-model array in the data of the same component, but it is obviously pretty useless if I want to make this component reusable and insert the v-model via props and for example check some of the boxes from "outside". So I tried following:
CheckBoxgroup.vue
<template>
<div>
<label v-for="day in allDays" :key="day">
<input v-model="checkedDays" type="checkbox" :value="day" />
<span>{{ day }}</span>
</label>
<div>Checked days: {{ checkedDays }}</div>
</div>
</template>
<script lang="ts">
import Vue from 'vue'
import { Component, Prop } from 'vue-property-decorator'
@Component
export default class CheckBoxGroup extends Vue {
@Prop() checkedDays!: string[]
@Prop() allDays!: string[]
}
</script>
Index.vue
<template>
<div>
<checkbox-group :checked-days="checkedDays" :all-days="allDays" />
</div>
</template>
<script lang="ts">
import { Vue, Component } from 'vue-property-decorator'
import CheckboxGroup from './checkBoxGroup.vue'
@Component({
components: { CheckboxGroup },
})
export default class Index extends Vue {
// This list would usually come from an API
allDays = ['Monday', 'Tuesday', 'Wednesday']
checkedDays = ['Monday']
}
</script>
So the code is working almost fine, but I am getting
[Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders...
Is there any way around it? Any help would be appriciated.
you can't mutate the parent state from the children directly, however you can emit the event from child to parent to mutate from there as below:
Vue.component('check-box-group', {
template: `
<div>
<label v-for="day in allDays" :key="day">
<input
v-model="checkedDays"
:value="day"
@click="$emit('update-checked-days', { newCheckedDay: day })"
type="checkbox"
/>
<span>{{ day }}</span>
</label>
<div>Checked days: {{ checkedDays }}</div>
</div>
`,
props: {
checkedDays: {
type: Array, default: () => ([])
},
allDays: {
type: Array, default: () => ([])
},
}
})
new Vue({
el: "#app",
data() {
return {
allDays: ['Monday', 'Tuesday', 'Wednesday'],
checkedDays: ['Monday']
}
},
methods: {
HandleUpdateCheckedDays({newCheckedDay}) {
const indexOfCheckedDay = this.checkedDays.findIndex(checkedDay => checkedDay === newCheckedDay)
if (indexOfCheckedDay === -1) { // if not exists then add to checkedDays
this.checkedDays.push(newCheckedDay)
} else {
this.checkedDays = this.checkedDays.filter((_, i) => i !== indexOfCheckedDay)
}
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.11/vue.min.js"></script>
<div id="app">
<check-box-group
:checked-days="checkedDays"
:all-days="allDays"
@update-checked-days="HandleUpdateCheckedDays"
/>
</div>
note: remember that TS class composition is deprecated.