Reputation: 697
I think this is a fairly common problem. You fetch a list from an api, and then you display that list via
<div v-for="item in items">
<checkbox v-model="item.checked">
</div>
Now My question is about the checked property. when iterating over a list of undefined length, of unknown keys, it seems the checked property has to be created and attached to the item object like so
computed: {
items () {
var newList = Object.assign([], this.rootList) // shallow clone the api list
for (var i of newList) {
i.checked = false
// or
Vue.set(i, 'checked', false)
}
return newList
}
However this is not making my checkbox reactive. But more importantly, this way of adding new properties to the rootList object clone, is this the best practice? and if so, why is this not reactive? Even when using Vue.set
Upvotes: 2
Views: 2096
Reputation: 5491
Computed properties are by default getter-only [...]
https://v2.vuejs.org/v2/guide/computed.html#Computed-Setter
Due to the limitations of modern JavaScript (and the abandonment of Object.observe), Vue cannot detect property addition or deletion. Since Vue performs the getter/setter conversion process during instance initialization, a property must be present in the data object in order for Vue to convert it and make it reactive.
https://v2.vuejs.org/v2/guide/reactivity.html#Change-Detection-Caveats
This might help: https://jsfiddle.net/eywraw8t/187063/
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="app">
<div v-for="item in items">
<input type="checkbox" v-model="item.checked"> {{ item.name }}
</div>
<button @click="fetch">Fetch more items</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
<script>
new Vue({
el: "#app",
data: {
items: []
},
methods: {
fetch() {
let itemsFromApiResponse = [
{ name: "Test 1" },
{ name: "Test 2" },
{ name: "Test 3" },
];
itemsFromApiResponse.forEach(item => this.items.push(Object.assign({ checked: false }, item)));
}
}
})
</script>
</body>
</html>
Upvotes: 1