As the error states, you cannot change a prop from a child. This is because Vue uses this parent - child flow:
With this structure, you assure that the parent's data is the only source of truth.
In order to change data, you need to emit it up to the parent. You almost had it in your example. Instead of emitting a change
event, you need to emit input
for v-model
to sync the changes.
This is more clear when you see the example from the docs:
<input v-model="searchText">
Is indeed the same as:
<input
v-bind:value="searchText"
v-on:input="searchText = $event.target.value"
>
However, since vue 2.3.0, you can now do changes to props via the .sync
modifier
Vue.component('date-picker', {
props: ['label'],
data: () => ({
date: null,
dateFormatted: null,
open: false
}),
created() {
this.date = this.$value;
},
methods: {
formatDate (date) {
if (!date) return null
const [year, month, day] = date.split('-')
return `${day}/${month}/${year}`
},
parseDate (date) {
if (!date) return null
const [day, month, year] = date.split('/')
return `${year}-${month.padStart(2, '0')}-${day.padStart(2, '0')}`
},
update() {
this.$emit('input', this.dateFormatted);
}
},
watch: {
date (val) {
this.dateFormatted = this.formatDate(this.date)
},
dateFormatted(val) {
this.update();
}
},
template:`
<v-menu
ref="open"
:close-on-content-click="false"
v-model="open"
:nudge-right="40"
lazy
transition="scale-transition"
offset-y
full-width
>
<v-text-field
slot="activator"
v-model="dateFormatted"
:label="label"
placeholder="dia/mês/ano"
@blur="date = parseDate(dateFormatted)"
></v-text-field>
<v-date-picker v-model="date" no-title @input="open = false"></v-date-picker>
</v-menu>
`
});
Vue.config.productionTip = false;
Vue.config.devtools=false
new Vue({
el: '#app',
data: () => ({
myDate: '2018-09-01'
})
});
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/vuetify.min.css" rel="stylesheet"/>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vuetify/1.2.0/vuetify.min.js"></script>
<div id="app">
<v-app>
<v-flex xs24>
<date-picker label="Select a date" v-model="myDate"></date-picker>
<br>
Current date: {{myDate}}
</v-flex>
</v-app>
</div>