Search code examples
arraysvue.jsgroupinglodashvuex

Group Array with ID and ParentId with vuejs / vuex


I have an object like this:

[

{"id":1,"parentId":null,"name":"Parent1"},

{"id":2,"parentId":null,"name":"Parent2"},

{"id":3,"parentId":null,"name":"Parent3"},

{"id":4,"parentId":1,"name":"Child1Parent1"},

{"id":5,"parentId":1,"name":"Child2Parent1"},

{"id":6,"parentId":2,"name":"Child1Parent2"},

{"id":7,"parentId":null,"name":"Parent4"}

... ]

I have to return grouped Array by Id and ParentId in table with expanded childs if exist like:

[

{

"id":1,"parentId":null,"name":"Parent1",

{"id":4,"parentId":1,"name":"Child1Parent1"},

{"id":5,"parentId":1,"name":"Child2Parent1"}

},

{

"id":2,"parentId":null,"name":"Parent2",

{"id":6,"parentId":2,"name":"Child1Parent2"}

},

{"id":3,"parentId":null,"name":"Parent3"},

... ]


Solution

  • I took the liberty to take @procoib's answer a bit further and I added a few more details to to it, allowing the markup to be more expressive:

    Vue.config.productionTip = false;
    Vue.config.devtools = false;
    new Vue({
      el: '#app',
      data: () => ({
        items: [
          { "id": 1, "parentId": null, "name": "Parent1" },
          { "id": 2, "parentId": null, "name": "Parent2" },
          { "id": 3, "parentId": null, "name": "Parent3" },
          { "id": 4, "parentId": 1, "name": "Child1Parent1" },
          { "id": 5, "parentId": 1, "name": "Child2Parent1" },
          { "id": 6, "parentId": 2, "name": "Child1Parent2" },
          { "id": 7, "parentId": null, "name": "Parent4" }
        ].map(i => ({ ...i,
          expanded: true
        }))
      }),
      computed: {
        parents() {
          return this.items.filter(g => !g.parentId)
        },
        children() {
          return this.items.filter(g => g.parentId)
        }
      },
      methods: {
        childrenOf(id) {
          return this.items.filter(g => g.parentId === id)
        }
      }
    })
    .cursor-pointer {
      cursor: pointer;
    }
    <link href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" rel="stylesheet" />
    <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.11/vue.js"></script>
    
    <div id="app">
      <table class="table table-sm">
        <thead>
          <tr>
            <th>ID</th>
            <th>parentId</th>
            <th>name</th>
          </tr>
        </thead>
        <tbody>
          <template v-for="parent in parents">
              <tr>
                <th colspan="3"
                    class="bg-light">
                    {{parent.name}}
                    <code v-if="childrenOf(parent.id).length"
                          class="font-weight-light cursor-pointer"
                          @click="parent.expanded = !parent.expanded">[{{
                            parent.expanded ? 'hide' : 'show'
                          }}]</code>
                </th>
              </tr>
              <tr v-for="child in childrenOf(parent.id)" v-show="parent.expanded">
                <td v-text="child.id" />
                <td v-text="child.parentId"/>
                <td v-text="child.name"/>
              </tr>
            </template>
        </tbody>
      </table>
    </div>