Home > Back-end >  How to create a table with indents from nested JSON in angularjs
How to create a table with indents from nested JSON in angularjs

Time:04-22

I get a nested JSON object back from an API call that looks something along the lines of this:

{
  "name": “Main “Folder”,
  "children": [
    {
      "name": “Child Folder 1”,
      "children": []
    },
    {
      "name": “Child Folder 2”,
      "children": [
        {
          "name": “Sub Folder 1”,
          "children": [
            {
                “name”: “Sub Sub Folder 1”,
                “children”: []
            }
          ]
        },
        {
          "name": “Sub Folder 2” ,
          "children": []
        }
      ]
    }
  ]
}

There is no limit on how far the JSON object can be nested so that is unknown to me. I need to have all of the children of the folders to be indented under the parent in the table. I'm not really even sure how to go about doing this. The first thing I tried was doing something like this in my HTML file, but I quickly realized it wasn't going to work.

folders.html

<table>
    <thead>
        <tr><strong>{{ this.tableData.name }}</strong></tr>
    </thead>
    <tbody ng-repeat="b in this.tableData.children">
        <tr>
            <td>{{ b.name }}</td>
            <td ng-repeat="c in b.children">{{ c.name }}</td>
        </tr>
    </tbody>
</table>

folders.js

export default class FoldersController {
  constructor($rootScope, $scope, $uibModal) {
      this.tableData = {Example Data from top}
  }
}

Is there a not too complicated way to go about doing this? Thanks!

CodePudding user response:

You should create a component with a template that contains a table, then you can nest your component inside itself to follow the tree structure logical path:

Your root controller should contain your table data:

angular.module('app').controller('RootCtrl', ['$scope', function($scope) {
    // assigning the data to $scope to make it available in the view
    $scope.tableData = {Example Data from top};
}]);

Your tree component could be something on this lines:

angular.module('app').component('treeComponent', {
    controller: 'TreeCtrl',
    bindings: {
        tree: '<',
    },
    templateUrl: 'tree-view.html'
});

your root template should load the first instance of the component:

<div>
   <tree-component tree="tableData"></tree-component>
</div>

then the component template should take care of the the recursion when required; tree-view.html:

<table >
    <thead>
        <tr>
           <th>
              <strong>{{ $ctrl.tableData.name }}</strong>
           </th> 
        </tr>
    </thead>
    <tbody>
        <tr ng-repeat="node in $ctrl.tableData.children">
            <td>{{node.name}}</td>
            <td ng-if="node.children.length > 0">
               <tree-component tree="node.children"></tree-component>
            </td>
        </tr>
    </tbody>
</table>

creating indentation then becomes easy using basic css:

.record-table .record-table {
   padding-left: 20px
}

CodePudding user response:

I was able to figure out a solution of my own using recursion in the js file. I implemented mindthefrequency's answer as well and it seems to be working just fine. I'm marking it as the best answer because it seems to be the cleaner solution, but I'm posting what I have in case someone wants to take a more js oriented approach.

First, in the js file, use recursion to add all of the nodes and how far each needs to be indented to the table data variable.

folders.js

export default class FoldersController {
  constructor($rootScope, $scope, $uibModal) {
      this.resp = {Example Data from top}
      this.tableData = []
      this.createTable(this.resp.children, 0, [
          {
            name: this.resp.name,
            indent: '0px',
          },
        ]);
  }

  createTable(children, count, data) {
    count  = 1;

    // base case
    if (!children || children.length === 0) {
      return;
    }

    for (const child of children) {
      const { name } = child;

      const returnData = data;
      returnData.push({
        name: name,
        indent: `${count * 25}px`,
      });

      this.tableData = returnData;

      this.createTable(child.children, count, returnData);
    }
  }
}

Then, in the html file, use angularjs to properly indent each node

folders.html

<table>
  <thead>
    <tr><strong>Table Header</strong></tr>
  </thead>
  <tbody ng-repeat="b in vm.tableData">
    <tr>
      <td ng-style="{'padding-left': b.indent}">{{ b.name }}</td>
    </tr>
  </tbody>
</table>
  • Related