First of all, I am just starting playing with VueJS, so this cannot be a VueJS version thing as suggested here
It might be a duplicate of :
v-bind
, once.My problem starts with my Html looking like this:
<div id="app">
<div class="row">
<div class="form-group col-md-8 col-md-offset-2">
<birthday-controls
:birthDay="birthDay"
:birthMonth="birthMonth"
:birthYear="birthYear">
</birthday-controls>
</div>
</div>
</div>
and JS:
Vue.component('birthday-controls', {
template: `<div class="birthday">
<input type="text" name="year" placeholder="yyyy" v-model="birthYear" size="4" maxlength="4"/>
<input type="text" name="month" placeholder="mm" v-show="validYear" v-model="birthMonth" size="3" maxlength="2"/>
<input type="text" v-show="validYear && validMonth" name="day" placeholder="dd" v-model="birthDay" size="2" maxlength="2"/>
</div>`,
props: ['birthDay', 'birthMonth', 'birthYear'],
computed: {
validYear: function() {
return (this.birthYear > new Date().getFullYear()-100 && this.birthYear < new Date().getFullYear()-14)
},
validMonth: function() {
return (this.birthMonth > 0 && this.birthMonth <= 12)
},
validDay: function() {
return (this.birthDay > 0 && this.birthDay <=31) //I have to add more checking here for february, leap years and ....
}
}
});
new Vue({
el: '#app',
data: function() {
return {
birthDay: "",
birthMonth: "",
birthYear: ""
}
},
});
I have prepared codepen here: http://codepen.io/AngelinCalu/pen/OpXBay
However, the second answer from here: vuejs update parent data from child component makes me realise that I'm missing something
In that example it sets an this.$emit('increment')
inside one of the methods, and triggers that on specific event.
In this other example: Update a child's data component to the father component in vue.js using .vue webpack(vue2) , the answer suggest adding a watch
to emit the change.
watch: {
val() {
this.$emit('title-updated', this.val);
}
}
Now I'm even more confused! What is the right (or best) way to deal with this problem?
Note:
If I remove from the initial html
:
:birthDay="birthDay"
:birthMonth="birthMonth"
:birthYear="birthYear"
It still works as expected, but I'm still getting that Vue warn, however, if I'm following the method from here: https://stackoverflow.com/a/41901150/2012740, it stops working, but I'm getting no error.
My Updated code: https://jsfiddle.net/angelin8r/647m7vdf/
To conclude: I need the functionality from the beginning but without the [Vue warn]
This is what I got in my initial example:
[Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "birthYear"
Error message: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value.
This rule applies when a prop of a Vue component is mutated inside the component. If a prop is mutated, Vue outputs a warning message because the mutated prop value will be overwritten whenever the parent component re-renders.
Short answer is: NO. Long answer is: It will not work.
The v-model directive makes two-way binding between a form input and app state very easy to implement. One can bind a form input element and make it change the Vue data property when the content of the field changes.
The warning is the result of setting v-model
to the value of your properties. The reason is because if you change birthYear, birthMonth, or birthDay outside the component, then whatever the value is currently inside the component will be immediately overwritten.
Instead, capture a copy.
Vue.component('birthday-controls', {
template: `<div class="birthday">
<input type="text" name="year" placeholder="yyyy" v-model="internalBirthYear" size="4" maxlength="4"/>
<input type="text" name="month" placeholder="mm" v-show="validYear" v-model="internalBirthMonth" size="3" maxlength="2"/>
<input type="text" v-show="validYear && validMonth" name="day" placeholder="dd" v-model="internalBirthDay" size="2" maxlength="2"/>
</div>`,
props: ['birthDay', 'birthMonth', 'birthYear'],
data(){
return {
internalBirthDay: this.birthDay,
internalBirthMonth: this.birthMonth,
internalBirthYear: this.birthYear
}
},
computed: {
validYear: function() {
return (this.internalBirthYear > new Date().getFullYear()-100 && this.internalBirthYear < new Date().getFullYear()-14)
},
validMonth: function() {
return (this.internalBirthMonth > 0 && this.internalBirthMonth <= 12)
},
validDay: function() {
return (this.internalBirthDay > 0 && this.internalBirthDay <=31) //I have to add more checking here for february, leap years and ....
}
}
});
You did this almost exactly in your fiddle, but you did not correct your computed values.
computed: {
validYear: function() {
return (this.birthYear > new Date().getFullYear()-100 && this.birthYear < new Date().getFullYear()-14)
},
validMonth: function() {
return (this.birthMonth > 0 && this.birthMonth <= 12)
},
validDay: function() {
return (this.birthDay > 0 && this.birthDay <=31) //I have to add more checking here for february, leap years and stuff
}
},
should be
computed: {
validYear: function() {
return (this.var_birthYear > new Date().getFullYear()-100 && this.var_birthYear < new Date().getFullYear()-14)
},
validMonth: function() {
return (this.var_birthMonth > 0 && this.var_birthMonth <= 12)
},
validDay: function() {
return (this.var_birthDay > 0 && this.var_birthDay <=31) //I have to add more checking here for february, leap years and stuff
}
},
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With