Skip to content
Advertisement

vue.js – recursive components doesn’t get updated when using nested array from raw json

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.

User contributions licensed under: CC BY-SA
5 People found this is helpful
Advertisement