AngularJS : Expandable recursive tree table AngularJS : Expandable recursive tree table angularjs angularjs

AngularJS : Expandable recursive tree table


You can consider using tree-grid.

demo: expandable grid

  <tree-gird tree-data="tree_data"></tree-grid>

Provide a tree structured data, column definition and a property where you want to expand.

Provide a tree structured data, column definition and a property where you want to expand in your controller.

 $scope.tree_data = [   {Name:"USA",Area:9826675,Population:318212000,TimeZone:"UTC -5 to -10",  children:[    {Name:"California", Area:423970,Population:38340000, TimeZone:"Pacific Time",        children:[            {Name:"San Francisco", Area:231,Population:837442,TimeZone:"PST"},            {Name:"Los Angeles", Area:503,Population:3904657,TimeZone:"PST"}        ]    },    {Name:"Illinois", Area:57914,Population:12882135,TimeZone:"Central Time Zone",        children:[            {Name:"Chicago", Area:234,Population:2695598,TimeZone:"CST"}        ]     }   ]  },      {Name:"Texas",Area:268581,Population:26448193,TimeZone:"Mountain"}];

Optionally, you can define column definitions, properties on which you want to use expand and collapse

$scope.col_defs = [   { field: "Description"},   { field: "DemographicId", displayName: "Demographic Id"},   { field: "ParentId", displayName: "Parent Id"},   { field: "Area"},   { field: "Population"},   { field: "TimeZone", displayName: "Time Zone"}];$scope.expanding_property = "Name";

details: https://github.com/khan4019/tree-grid-directive


Add ng-if here

<div id="expanded-data" data-ng-if="childrenVisible">

and give your tree items a property which defines the visibility of their children.Set the property true or false (if you want false just dont add it by default) by default and implement a toggleChildren function which is called by a click on the toggleButton (the folder)

scope.toggleChildren = function () {    scope.item.childrenVisible = !scope.item.childrenVisible;}

EDIT:// Now changing the folder (opened or closed)http://jsfiddle.net/8f3rL/35/


Use this table, with all CRUD operations and user friendly indentation :-

How to display tree data structure using Angularjs-1 and bootstral html table?


treeDS.html

<!doctype html><html><head>    <title>Testbook: Admin App</title>    <link rel="stylesheet" type="text/css" href="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css">    <style>        .level0{            text-indent : 0px;            color : #428bca;        }        .level1{            text-indent : 20px;            color : #428bca;        }        .level2{            text-indent : 40px;            color : #428bca;        }        .level3{            text-indent : 60px;            color : #428bca;        }        .level4{            text-indent : 80px;            color : #428bca;        }        .level5{            text-indent : 100px;            color : #428bca;        }        .level6{            text-indent : 120px;            color : #428bca;        }        .hasDropdown{            color : #428bca ;        }        .noDropdown{            color : #000000;        }        div.tooltip-inner {            text-align: center;            -webkit-border-radius: 0px;            -moz-border-radius: 0px;            border-radius: 0px;            margin-bottom: 6px;            background-color: #505050;            font-size: 14px;        }    </style></head><body  ng-app="treeDataStructureApp" ng-controller="treeDataStructureCtrl">    <div class="container-fluid" style="padding-left : 25px;">        <br><br><br>        <div class="row">            <div class="col-md-8 col-md-offset-2">                <span class="label label-default ng-binding" style="font-size : 25px">                    Tree Data Structure Implementation Using Bootstrap Table                </span>            </div>        </div>        <br><br><br>        <div class="row">            <div class="col-md-3">                <button ng-click="addNewNodeAtRootLevel()" type="button" class="btn btn-primary btn-sm">Add New Node</button>            </div>        </div>        <br>        <div class="row">            <div class="col-md-12">                    <table class="table table-hover table-bordered" id="mytable" style="width: 90%;">                        <caption></caption>                        <thead>                        <tr class="info">                            <th                            data-toggle="tooltip" data-placement="top" title="click here to expand/close"                            ng-click="expandAll()">                            Name                            <span ng-if="!showAll" class="glyphicon glyphicon-triangle-right"                                   aria-hidden="true"                                   data-toggle="tooltip" data-placement="top" title="Help: expand all nodes">                            </span>                            <span ng-if="showAll" class="glyphicon glyphicon-triangle-bottom"                                   aria-hidden="true"                                   data-toggle="tooltip" data-placement="top" title="Help: ">                            </span>                            </th>                            <th>Id</th>                            <th>Operations</th>                        </tr>                        </thead>                        <tbody>                            <tr ng-repeat="node in nodesTableArr | filter : {isShow : true }" ng-class=" colorBackgroundOfNewnode(node)" >                                <td ng-class="[hasDropdown(node), selectIndentationClass(node)]">                                    <span ng-model="node.editable" contenteditable='node.isEditable' ng-click="toggleDropdown(node)"> {{node.name}}</span>                                </td>                                <td contenteditable='false'> {{node.id}} </td>                                <td contenteditable='false'>                                    <span ng-click="addChildNode(node)" class="glyphicon glyphicon-plus" aria-hidden="true"                                      data-toggle="tooltip" data-placement="top" title="Help: add new node under this node edit its name and press save button,save button will show after editing its name">                                        </span>                                    <span ng-click="deleteNode(node, 'concept')" class="glyphicon glyphicon-minus"                                           aria-hidden="true"                                           data-toggle="tooltip" data-placement="top" title="Help: delete this node, all nodes under it will also be deleted">                                    </span>                                    <span ng-click="editNode(node)" class="glyphicon glyphicon-edit"                                           aria-hidden="true"                                           data-toggle="tooltip" data-placement="top" title="Help: edit name and then press update button, update button will show, after editing its name">                                    </span>                                    <button ng-click="saveNewNodeCB (node, false)" type="button"                                             class="btn btn-primary btn-xs" ng-show="node.isSaveBtn">save                                    </button>                                    <button ng-click="updateNode(node)" type="button" class="btn btn-primary btn-xs"                                             ng-show="node.isUpdateBtn">update                                    </button>                                    <span ng-medel="operationStatusMessage" ng-show="node.isShowMessage">                                         <small>{{operationStatusMessage}} </small>                                    </span>                                </td>                            </tr>                        </tbody>                    </table>                </div>            </div>        </div>        <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.15/angular.min.js" type="text/javascript"></script>        <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.15/angular-route.min.js" type="text/javascript"></script>        <script src="http://angular-ui.github.io/bootstrap/ui-bootstrap-tpls-0.12.1.js" type="text/javascript"></script>        <script src="treeDS.js" type="text/javascript"></script>  </body>


treeDS.js file

/** * Created by Aditya on 15/10/2015. */'use strict';

var app = angular.module('treeDataStructureApp',[]); app.controller('treeDataStructureCtrl', ['$scope',function ($scope){

// add new node at top level here    $scope.isAddExamNode = false;    $scope.addNewNodeAtRootLevel = function(){        $scope.isAddExamNode = true;        var newNode = {                    name: "new node",                    id : "",                    level: 0,                    parent: "root",                    toggleStatus : false,                    parentId : -1,                    isShow: true,                    isEditable : false,                    childCount: 0,                    isSaveBtn : false,                    isShowMessage : false,                    type : "exam"                };       $scope.nodesTableArr.unshift(newNode);       };    // add new node.    $scope.operationStatusMessage = "";    $scope.currentNodeSelected = {};    var uniqueIdForNewNodes = 0;    $scope.addChildNode = function(node){        // add row to table.        $scope.operationStatusMessage = "";        $scope.currentNodeSelected = node;        for (var i = 0; i < $scope.nodesTableArr.length; i++) {            if($scope.nodesTableArr[i].id == node.id){                $scope.nodesTableArr.splice(i + 1, 0, {                    name: "new node",                    id : uniqueIdForNewNodes,                    level: node.level + 1,                    parent: node.name,                    toggleStatus : false,                    parentId : node.id,                    isShow: true,                    isEditable : false,                    childCount: 0,                    isSaveBtn : false,                    isShowMessage : false,                    type : "nonExam"                });                break;            }        }        uniqueIdForNewNodes += 1;    };    $scope.saveNewNode = function(node, isExamNode){        alert("You can send request on server to add this node here.");        $scope.saveNewNodeCB();    };    $scope.saveNewNodeCB = function(){            $scope.resetOperationStatusMessage();            $scope.operationStatusMessage = "node Saved Successfully";            $scope.currentNodeSelected.isShowMessage = true;            $scope.currentNodeSelected.isSaveBtn = false;            // update node id in newly added node object, so that if we add new node under it, it has its valid parent id.            for(var i = 0 ; i < $scope.nodesTableArr.length ; i++){                var node = $scope.nodesTableArr[i];                if(node == $scope.conceptNodeToAdd)                    node.id = response.data.node;            }            alert("send request to server here to save this node.");    };    $scope.editNode = function(node){        $scope.nodeNameInOperation = node.name;        $scope.operationStatusMessage = "";        $scope.currentNodeSelected = node;        var nodeName = prompt("Please enter New node Name", node.name);        if(nodeName != "" && nodeName != null && node.name != undefined && nodeName != node.name){          node.name = nodeName;          if(node.id != ""){              node.isUpdateBtn = true;          }          else{              node.isSaveBtn = true;          }        }    };    $scope.updateNode = function(node){        alert("You can send request on server to update this node.");        $scope.updateNodeCB();    };    $scope.updateNodeCB = function(response){                        $scope.resetOperationStatusMessage();        if(true){            $scope.currentNodeSelected.isShowMessage = true;            $scope.operationStatusMessage = "node Updated Successfully";            $scope.currentNodeSelected.isUpdateBtn = false;        }    };    // nodeType = concept/nonConcept    $scope.nodeToDelete = {};    $scope.deleteNode = function(node, nodeType){        $scope.nodeNameInOperation = node.name;        $scope.nodeTypeForMessage = nodeType;        $scope.nodeToDelete = node;        $scope.operationStatusMessage = "";        $scope.currentNodeSelected = node;        var message;        if(node.id == ""){            for(var i = 0 ; i < $scope.nodesTableArr.length ; i++){                if($scope.nodesTableArr[i] == $scope.currentNodeSelected)                    $scope.nodesTableArr.splice(i, 1);            }            return 0 ;        }        var r = confirm("Warning! Be Carefull! On deletion all nodes under this node will be deleted.\nPress ok to delete node");        if (r == true) {            $scope.deleteNodeCB();            message = "nodes deleted successfully.";        } else {            message = "process cancelled.";        }        $scope.curPageNo = 1;    };    $scope.deleteNodeCB = function(){      $scope.resetOperationStatusMessage();      $scope.operationStatusMessage = "node deleted Successfully";      $scope.currentNodeSelected.isShowMessage = true;      for(var i = 0 ; i < $scope.nodesTableArr.length ; i++){          if($scope.nodesTableArr[i] == $scope.currentNodeSelected)              $scope.nodesTableArr.splice(i, 1);      }    };    $scope.resetOperationStatusMessage = function(){        for(var i = 0 ; i < $scope.nodesTableArr.length ; i++){            $scope.nodesTableArr[i].isShowMessage = false;        }    };    // concept nodes related operations ends here    var node = "";    $scope.nodesTableArr = [];    $scope.initializeNodeTreeTable = function(pChildArr){        var length = pChildArr.length || 0;        for(var i = 0 ; i < length ; i++){             var exam = pChildArr[i];            var level = 0;            var childCount = 0;            if(exam.children && exam.children.length)                childCount = exam.children.length;            $scope.nodesTableArr.push({name : exam.text, id : exam._id, parent : "root", toggleStatus : false,             parentId : -1, isShow : true, isEditable : false, level : 0, childCount : childCount,             isSaveBtn : false, isUpdateBtn : false                });            if(exam.children != undefined)            $scope.initializeNodeTreeTableHelper(exam.children, exam.text, exam._id, level);        }    };    $scope.initializeNodeTreeTableHelper = function(pChildArr, pParentName, pPparentId, pLevel){        var isShowNode = false;        pLevel = pLevel + 1 ;        for(var i = 0 ; i < pChildArr.length ; i++){            var node = pChildArr[i];            var childCount = node.children != undefined ? node.children.length : 0            $scope.nodesTableArr.push({name : node.text, id : node._id, parent : pParentName, toggleStatus : false,             parentId : pPparentId, isShow : isShowNode, isEditable : false, level : pLevel, childCount : childCount,             isSaveBtn : false, isUpdateBtn : false            });            if(node.children != undefined)                $scope.initializeNodeTreeTableHelper(node.children, node.text, node._id, pLevel)        }    };    $scope.selectedExam = "";    $scope.renderNodeTreeForExam = "selectedExamNode";    $scope.renderNodeTreeForExam = function(exam){        $scope.nodesTableArr = [];        $scope.selectedExam = exam;        var selectedExamArr = [exam];        if($scope.selectedExam == "allExams")            selectedExamArr = $scope.allExams        $scope.getAllNodes(selectedExamArr);    };    // view related functions.    $scope.selectIndentationClass = function(node){        return 'level' + node.level;    };    $scope.hasDropdown = function(node){        if(node.childCount > 0)            return "hasDropdown";        else            return "noDropdown";    };    $scope.colorBackgroundOfNewNode = function(node){        if(node.id == ""){            return "success";        }    };    $scope.toggleStatus = false;    $scope.toggleDropdown = function(node){        node.toggleStatus = node.toggleStatus == true ? false : true;        $scope.toggleStatus = node.toggleStatus;        $scope.toggleDropdownHelper(node.id, $scope.toggleStatus );    };    $scope.toggleDropdownHelper = function(parentNodeId, toggleStatus ){        for(var i = 0 ; i < $scope.nodesTableArr.length ; i++) {            node = $scope.nodesTableArr[i];            if(node.parentId == parentNodeId) {                if(toggleStatus == false)                $scope.toggleDropdownHelper(node.id, toggleStatus);                $scope.nodesTableArr[i].isShow = toggleStatus;            }        }    };    $scope.showAll = false;    $scope.expandAll = function(){        var  i = 0;        $scope.showAll = $scope.showAll == true ? false : true;        if($scope.showAll) {            for (i = 0; i < $scope.nodesTableArr.length; i++)                $scope.nodesTableArr[i]['isShow'] = true;        }        else {            for (i = 0; i < $scope.nodesTableArr.length; i++)                if($scope.nodesTableArr[i]['level'] != 0)                  $scope.nodesTableArr[i]['isShow'] = false;        }    };    $scope.initializeNodeTreeTable(sampleData.data)}]); var sampleData = {  "data": [    {  "_id": "557569e82a39650f65425104",  "depth": 0,  "text": "SBI Clerk",  "exam": "SBI Clerk",  "children": [    {      "_id": "55c2dee72a3965432eaac6a7",      "depth": 1,      "text": "Quantitative Aptitude",      "exam": "SBI Clerk",      "children": [        {          "_id": "55c2dee72a3965432eaac6a8",          "depth": 2,          "text": "Simplification",          "exam": "SBI Clerk",          "children": [            {              "_id": "55c2dee72a3965432eaac6a9",              "depth": 3,              "text": "Bodmas Rule",              "exam": "SBI Clerk",              "type": "topic",              "par": "Bodmas Rule"            },            {              "_id": "55c2dee72a3965432eaac6aa",              "depth": 3,              "text": "Surds And Indices",              "exam": "SBI Clerk",              "type": "topic",              "par": "Surds And Indices"            },            {              "_id": "55c2dee82a3965432eaac6ab",              "depth": 3,              "text": "Approx Value",              "exam": "SBI Clerk",              "type": "topic",              "par": "Approx Value"            },            {              "_id": "55c2dee82a3965432eaac6ac",              "depth": 3,              "text": "Percennodee",              "exam": "SBI Clerk",              "type": "topic",              "par": "Percennodee"            }          ],          "type": "chapter",          "par": "Simplification"        }      ],      "type": "subject",      "par": "Quantitative Aptitude"    }  ],  "type": "exam",  "par": ""}  ]};

jsFiddle : Working Example

http://jsfiddle.net/Aditya199121/y0te91dm/1/