Join the Stack Overflow Community
Stack Overflow is a community of 6.7 million programmers, just like you, helping each other.
Join them; it only takes a minute:
Sign up

I'm new to VUE, and having a hard time figuring out how to render an Object where i don't know how many levels deep it will go.

i get this object returned from a web-api

var result = {  
               "1":{  
                  "id":"1",
                  "parent_id":"-1",
                  "name":"Master",
                  "level":1,
                  "children":{  
                     "2":{  
                        "id":"2",
                        "parent_id":"1",
                        "name":"Category A",
                        "level":2,
                        "children":{  
                           "5":{  
                              "id":"5",
                              "parent_id":"2",
                              "name":"Category D",
                              "level":3
                           },
                           "6":{  
                              "id":"6",
                              "parent_id":"2",
                              "name":"Category E",
                              "level":3,
                              "children":{  
                                 "10":{  
                                    "id":"10",
                                    "parent_id":"6",
                                    "name":"Category F",
                                    "level":4
                                 }
                              }
                           }
                        }
                     },
                     "3":{  
                        "id":"3",
                        "parent_id":"1",
                        "name":"Category B",
                        "level":2,
                        "children":{  
                           "4":{  
                              "id":"4",
                              "parent_id":"3",
                              "name":"Category C",
                              "level":3
                           }
                        }
                     }
                  }
               }
            };

I ignore the first level and push it in my store. Now i'm looking for a recursive way to go over all the parent's and theire children. (this would be an example of the desired output)

<ul>
  <li>Master</li>
    <ul>
      <li>Category A</li>
      <ul>
        <li>Category D</li>
        <li>Category E</li>
        <ul>
          <li>Category F</li>
        </ul>
      </ul>
      <li>Category B</li>
      <ul>
        <li>Category C</li>
      </ul>
   </ul>
</ul>

However i do not get further then:

<ul>
  <li>Master</li>
  <ul>
    <li>Category A</li>
    <li>Category B</li>
   </ul>
</ul>  

And offcourse i could go on like this and then i'll reach the end of my obj. but in real situation i don't know how deep it will go, that's why i want a solution that doesn't care about that and continiu's till there are no more children.

I saw a little something in the doc's but that code is so different from mine that i cant really understand how to apply ( https://vuejs.org/v2/guide/components.html#Circular-References-Between-Components )

My init code is basically this is everything (simplified) together :

store = function()  {
    var self = this;
    self.hierarchies  = [];
    self.subView = 'hierarchies';
    self.tree = [];
};

Vue.component('hierarchies', {
    template: '#hierarchies',
    props: ['store']
});

Vue.component('products', {
    template: '#products',
    props: ['store']
});

Vue.component('treeview', {
    template: '#treeview',
    props: ['store']
});

app = new Vue({
    el: '#content',
    data: function () {
        return {
            store: {},
            tree: {}
        }
    },
    created: function () {
        this.store = new store();
    }
});


// DO AXJAX REQUEST GET HIERARCHY'S
var response = // AJAX  {};
app.store.tree.push(response[1]);
<template id="treeview">
    <div>
        <ul v-if="store.tree.length">
            <li v-for="m in store.tree">
                {{ m.name }}
                <ul v-if="m.children">
                    <li v-for="c in m.children">
                        {{ c.name }}
                    </li>
                </ul>
                <data :tree="m"></data>
            </li>
        </ul>
    </div>
</template>

All idea's suggestions are welcome :)

Best, Bastian

share|improve this question
up vote 1 down vote accepted

Your data is in a pretty unpractical format since you cannot loop over object keys using the v-for directive. So in order to consume that format, you have to transform it into an array first. I’m using a computed property for that, but a better solution for the long run might be to transform the data once in the beginning or even changing the result format of your web service (if you can).

var result = {"1":{"id":"1","parent_id":"-1","name":"Master","level":1,"children":{"2":{"id":"2","parent_id":"1","name":"Category A","level":2,"children":{"5":{"id":"5","parent_id":"2","name":"Category D","level":3},"6":{"id":"6","parent_id":"2","name":"Category E","level":3,"children":{"10":{"id":"10","parent_id":"6","name":"Category F","level":4}}}}},"3":{"id":"3","parent_id":"1","name":"Category B","level":2,"children":{"4":{"id":"4","parent_id":"3","name":"Category C","level":3}}}}}};

Vue.component('tree-root', {
  props: ['items'],
  template: `
    <ul>
      <tree-item v-for="item in items" v-bind:item="item"></tree-item>
    </ul>
  `
});

Vue.component('tree-item', {
  props: ['item'],
  computed: {
    children: function () {
      return Object.keys(this.item.children).map(k => this.item.children[k]);
    }
  },
  template: `
    <li>
      {{item.name}}
      <tree-root v-if="item.children" v-bind:items="children"></tree-root>
    </li>
  `
});

var app = new Vue({
  el: '#app',
  data: {
    rootItem: result['1']
  }
});
<ul id="app">
  <tree-item v-bind:item="rootItem"></tree-item>
</ul>

<script src="https://unpkg.com/vue/dist/vue.js"></script>

What I’m doing here is use two components: tree-root which is responsible for rendering a list of items, and tree-item which is responsible for rendering a single item, eventually recursively rendering another tree-root for the children of each item.

The computed children property is used to transform the children object into a list of children.

Finally, in order to render the root component, we just render the result['1'] which is the root element as a tree-item. We could also render a tree-root instead with the whole result but then we would have to convert it first into an array (just like in the computed property), so I just opted with the simpler solution here.

share|improve this answer
    
Thank you Poke, for the very extensive and well explained reply. Based on your sample i got it working! Awesome, this made my day :-) – Bastian Nov 15 '16 at 23:01
    
@Bastian Glad I could help! Please remember to upvote helpful answers and to ultimately accept the answer that solved your problem to mark the question as resolved. – poke Nov 16 '16 at 7:37

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.