I am trying to create a tree with an add function using computed data. I used the tree-view example in vuejs official homepage and combined it with the computed function that I created but found no luck in implementing it. I’ve been trying to solve this for 4 days already and still no luck so I am here looking for help.
When you click the “+” in the end of the list it will trigger a call to the addChild
function and it will successfully append the data. The data gets appended but the recursive component is not reactive.
https://jsfiddle.net/znedj1ao/9/
var data2 = [{ "id": 1, "name":"games", "parentid": null }, { "id": 2, "name": "movies", "parentid": null }, { "name": "iron-man", "id": 3, "parentid": 2 }, { "id": 4, "name": "iron-woman", "parentid": 3 } ] // define the item component Vue.component('item', { template: '#item-template', props: { model: Object }, data: function () { return { open: false } }, computed: { isFolder: function () { return this.model.children && this.model.children.length } }, methods: { toggle: function () { if (this.isFolder) { this.open = !this.open } }, changeType: function () { if (!this.isFolder) { Vue.set(this.model, 'children', []) this.addChild() this.open = true } }, addChild: function () { this.model.children.push({ name: 'My Tres', children: [ { name: 'hello' }, { name: 'wat' } ] }) } } }) // boot up the demo var demo = new Vue({ el: '#demo', data: { treeData2: data2 }, computed: { nestedInformation: function () { var a= this.nestInformation(data2); return a; } }, methods: { nestInformation: function(arr, parent){ var out = [] for(var i in arr) { if(arr[i].parentid == parent) { var children = this.nestInformation(arr, arr[i].id) if(children.length) { arr[i].children = children } out.push(arr[i]) } } return out } } })
<!-- item template --> <script type="text/x-template" id="item-template"> <li> <div :class="{bold: isFolder}" @click="toggle" @dblclick="changeType"> {{model.name}} <span v-if="isFolder">[{{open ? '-' : '+'}}]</span> </div> <ul v-show="open" v-if="isFolder"> <item class="item" v-for="model in model.children" :model="model"> </item> <li class="add" @click="addChild">+</li> </ul> </li> </script> <p>(You can double click on an item to turn it into a folder.)</p> <!-- the demo root element --> <ul id="demo"> <item class="item" :model="nestedInformation[1]"> </item> </ul>
Advertisement
Answer
The Vue.js documentation that Abdullah Khan linked to in a comment above says:
Again due to limitations of modern JavaScript, Vue cannot detect property addition or deletion.
However, property addition is exactly what you are doing in your nestInformation
method:
if(children.length) { arr[i].children = children }
The result is that the children
property of each object is not reactive, so when this Array is pushed to in addChild
, no re-render is triggered in the UI.
The solution will be to use Vue.set when creating the children
Arrays so that they will be reactive properties. The relevant code in the nestInformation
method must be updated to the following:
if (children.length) { Vue.set(arr[i], 'children', children); }
I have forked and modified your fiddle for reference.