Reputation: 51
I'm using an object items
to show a list of inputs with v-for
.
items
is updated when the component mounted
, but it only shows two inputs at first.
The third input will display after clicking the button or typing in the input. But the items
value doesn't update when the third input changes.
I was wondering
window.onload = () => {
new Vue({
el: '#app',
data() {
return {
show: true,
items: {
peter: {
name: 'Peter',
value: ''
},
kitty: {
name: 'Kitty',
value: ''
}
},
}
},
watch: {
show(newVal) {
console.log('Alert is now ' + (newVal ? 'visible' : 'hidden'))
}
},
mounted() {
this.items.test = {
name: 'Test',
value: ''
}
},
methods: {
toggle() {
console.log('Toggle button clicked')
this.show = !this.show
},
}
})
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div>
<button @click="toggle">
{{ show ? 'Hide' : 'Show' }} Alert
</button>
<div v-if="show">
Hello!
</div>
<div v-for="(item,index) in items" :key="index">
<label>{{item.name}}:</label>
<input type="text" name="item.name" v-model="items[index].value" />
</div>
<div>{{items}}</div>
</div>
</div>
Upvotes: 0
Views: 1567
Reputation: 27202
Vue has a different way of tracking when it comes to update the UI
Vue uses getters/setters on the data object for mutation tracking. When you execute this.items = [{}, {}, {}, ...];
, It will go through the setter of table. In the setter, there's a function to notify the watcher and add this data changes to a queue.
Vue cannot detect the following changes to an array :
vm.items[indexOfItem] = newValue
vm.items.length = newLength
Answer of your Question : In consideration of above two statements, You have to update whole array including the unmodified rows.
Upvotes: 0
Reputation: 845
Vue documentation describe this case
Vue does not allow dynamically adding new root-level reactive properties to an already created instance. However, it’s possible to add reactive properties to a nested object using the Vue.set(object, propertyName, value) method:
You can also use the vm.$set instance method, which is an alias to the global Vue.set:
https://v2.vuejs.org/v2/guide/reactivity.html#For-Objects
window.onload = () => {
new Vue({
el: '#app',
data() {
return {
show: true,
items: {
peter: {
name: 'Peter',
value: ''
},
kitty: {
name: 'Kitty',
value: ''
}
},
}
},
watch: {
show(newVal) {
console.log('Alert is now ' + (newVal ? 'visible' : 'hidden'))
}
},
mounted() {
this.$set(this.items, 'test', {
name: 'Test',
value: ''
})
/*
this.items.test = {
name: 'Test',
value: ''
}
*/
},
methods: {
toggle() {
console.log('Toggle button clicked')
this.show = !this.show
},
}
})
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div>
<button @click="toggle">
{{ show ? 'Hide' : 'Show' }} Alert
</button>
<div v-if="show">
Hello!
</div>
<div v-for="(item,index) in items" :key="index">
<label>{{item.name}}:</label>
<input type="text" name="item.name" v-model="items[index].value" />
</div>
<div>{{items}}</div>
</div>
</div>
Upvotes: 1