At some point in time of the ponent’s work, one of its values from the primitive turns into an object. This object is dynamically assigned fields with values. It is necessary to track the change in these values.
Simplified code to reproduce the problem:
const fields = ['name', 'age'];
const app = new Vue({
el: '#app',
data() {
return {
value: '',
};
},
watch: {
value: function() {
console.log('Global: Value changed');
},
},
mounted() {
this.value = '111';
this.value = {};
fields.forEach(field => {
this.value[field] = '';
});
this.$watch('value', callback, { deep: true });
function callback() {
console.log('Callback: Value changed');
}
this.$nextTick(() => {
this.value.name = 'Max';
this.value.age = 30;
console.log(this.value)
});
},
});
<script src="/[email protected]"></script>
<div id="app"></div>
At some point in time of the ponent’s work, one of its values from the primitive turns into an object. This object is dynamically assigned fields with values. It is necessary to track the change in these values.
Simplified code to reproduce the problem:
const fields = ['name', 'age'];
const app = new Vue({
el: '#app',
data() {
return {
value: '',
};
},
watch: {
value: function() {
console.log('Global: Value changed');
},
},
mounted() {
this.value = '111';
this.value = {};
fields.forEach(field => {
this.value[field] = '';
});
this.$watch('value', callback, { deep: true });
function callback() {
console.log('Callback: Value changed');
}
this.$nextTick(() => {
this.value.name = 'Max';
this.value.age = 30;
console.log(this.value)
});
},
});
<script src="https://cdn.jsdelivr/npm/[email protected]"></script>
<div id="app"></div>
Share
Improve this question
asked Aug 30, 2019 at 10:34
DmytroDmytro
3726 silver badges15 bronze badges
3 Answers
Reset to default 4The critical line is this.value = ...
. That's the point where the object will be made reactive and all properties need to exist at that point.
Here I've tweaked that section to add the properties before assigning the object to this.value
.
const fields = ['name', 'age'];
const app = new Vue({
el: '#app',
data() {
return {
value: '',
};
},
watch: {
value: function() {
console.log('Global: Value changed');
},
},
mounted() {
this.value = '111';
const value = {}
fields.forEach(field => {
value[field] = '';
});
this.value = value;
this.$watch('value', callback, { deep: true });
function callback() {
console.log('Callback: Value changed');
}
this.$nextTick(() => {
this.value.name = 'Max';
this.value.age = 30;
console.log(this.value)
});
},
});
<script src="https://cdn.jsdelivr/npm/[email protected]"></script>
<div id="app"></div>
Alternatively you can use this.$set
to set them later: https://v2.vuejs/v2/api/#vm-set.
Vue.$set(object, key, value)
can be helpful here:
const fields = ['name', 'age'];
const app = new Vue({
el: '#app',
data() {
return {
value: '',
};
},
watch: {
value: {
handler: function(value) {
console.log('Global: Value changed', value);
},
deep: true
}
},
mounted() {
let value = {};
fields.forEach(field => {
value[field] = '';
});
this.$set(this, 'value', value);
this.$nextTick(() => {
this.value.name = 'Max';
this.value.age = 30;
console.log(this.value)
});
},
});
<script src="https://cdn.jsdelivr/npm/[email protected]"></script>
<div id="app"></div>
this is called reactivity Caveat
https://v2.vuejs/v2/guide/reactivity.html#Change-Detection-Caveats
so to solve this issue you can import vue
import Vue from 'vue'
and then where you want to change values of an object
fields.forEach(field => {
//this.value[field] = ''; // instead of this
Vue.set(this.value, 'field', '')
});
OR
this.$set(this.value, 'field', '')