Check out this Angular tree table with the checkboxes code snippet. It provides a hierarchical tree structure with checkboxes for each item. The code allows you to toggle the selection of individual items and also provides an option to select/deselect all items at once.
The tree table consists of different categories each containing multiple nested items. You can easily integrate this code into your Angular application to implement a tree table with checkboxes for efficient data selection.
How to Create a Tree Table With Checkboxes
First of all, load the following assets into the head tag of your HTML document.
<link rel='stylesheet' href='https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.2.0/css/font-awesome.min.css'>
Create the HTML structure for tree table as follows:
<div class="wrapper" ng-app="testApp" ng-controller="treeTable"> <table class="table-nested"> <thead> <tr> <th class="cell-input"> <input ng-checked="(list | selected).length == list.length" ng-click="toggleAllCheckboxes($event)" type="checkbox" /> </th> <th> Name </th> <th class="cell-members"> Members </th> <th> Title </th> </tr> </thead> <tbody ng-class="{opened: item.opened}" ng-include="'table_tree.html'" ng-repeat="item in list"></tbody> </table> <script id="table_tree.html" type="text/ng-template"> <tr ng-class="{parent: item.children}" ng-init="parentScope = $parent.$parent; initCheckbox(item, parentScope.item)"> <td class="cell-input"> <input ng-change="toggleCheckbox(item, parentScope)" ng-model="item.selected" type="checkbox" /> </td> <td class="cell-name" ng-click="item.opened = !item.opened"> <div class="indent" style="padding-left: {{15*level}}px"></div> {{item.name}} </td> <td class="cell-members"> {{item.children.length}} </td> <td> {{item.title}} </td> </tr> <tr class="children" ng-if="item.children && item.children.length > 0"> <td colspan="4"> <table> <tbody ng-class="{opened: item.opened}" ng-include="'table_tree.html'" ng-init="level = level + 1" ng-repeat="item in item.children"></tbody> </table> </td> </tr> </script> </div>
Style the table using the following CSS styles. These styles are optional, you can define your own CSS according to your needs.
@charset "UTF-8"; body { font: 13px helvetica; width: 80%; margin: 40px auto; background: #eee; text-align: center; } table { width: 100%; table-layout: fixed; border-collapse: collapse; border-spacing: 0; } .table-nested { background: #fff; border: 2px solid #444; text-align: left; } .table-nested th, .table-nested td { padding: 0; } .table-nested th + th, .table-nested th + td, .table-nested td + th, .table-nested td + td { padding-left: 5px; } .table-nested td { border-top: 1px solid; } .table-nested td[colspan] { border: none; } .table-nested .cell-input { width: 20px; border-right: 1px solid; } .table-nested .cell-members { width: 100px; } .table-nested .indent { display: inline-block; } .table-nested .parent > .cell-name { cursor: pointer; } .table-nested .parent > .cell-name > .indent { margin-right: 5px; } .table-nested .parent > .cell-name > .indent:before { content: ""; font-family: FontAwesome; display: inline-block; -moz-transition: -moz-transform 0.3s; -o-transition: -o-transform 0.3s; -webkit-transition: -webkit-transform 0.3s; transition: transform 0.3s; } .table-nested .children { display: none; } .table-nested .opened > tr > .cell-name > .indent:before { -moz-transform: rotate(90deg); -ms-transform: rotate(90deg); -webkit-transform: rotate(90deg); transform: rotate(90deg); } .table-nested .opened > .children { display: table-row; }
Now, make sure you have loaded AngularJS into your project. You can load the AngularJS by adding the following CDN link before closing the body tag:
<script src='//ajax.googleapis.com/ajax/libs/angularjs/1.3.2/angular.min.js'></script>
Finally, add the following JavaScript function to active the tree table:
(function() { var app, list; list = [ { name: 'Developer', opened: true, children: [ { name: 'Front-End', children: [ { name: 'Jack', title: 'Leader' }, { name: 'John', title: 'Senior F2E' }, { name: 'Jason', title: 'Junior F2E' } ] }, { name: 'Back-End', children: [ { name: 'Mary', title: 'Leader' }, { name: 'Gary', title: 'Intern' } ] } ] }, { name: 'Design', children: [ { name: 'Freeman', title: 'Designer' } ] }, { name: 'S&S', children: [ { name: 'Nikky', title: 'Robot' } ] } ]; app = angular.module('testApp', []).controller('treeTable', [ '$scope', '$filter', function($scope, $filter) { $scope.list = list; $scope.toggleAllCheckboxes = function($event) { var i, item, len, ref, results, selected; selected = $event.target.checked; ref = $scope.list; results = []; for (i = 0, len = ref.length; i < len; i++) { item = ref[i]; item.selected = selected; if (item.children != null) { results.push($scope.$broadcast('changeChildren', item)); } else { results.push(void 0); } } return results; }; $scope.initCheckbox = function(item, parentItem) { return item.selected = parentItem && parentItem.selected || item.selected || false; }; $scope.toggleCheckbox = function(item, parentScope) { if (item.children != null) { $scope.$broadcast('changeChildren', item); } if (parentScope.item != null) { return $scope.$emit('changeParent', parentScope); } }; $scope.$on('changeChildren', function(event, parentItem) { var child, i, len, ref, results; ref = parentItem.children; results = []; for (i = 0, len = ref.length; i < len; i++) { child = ref[i]; child.selected = parentItem.selected; if (child.children != null) { results.push($scope.$broadcast('changeChildren', child)); } else { results.push(void 0); } } return results; }); return $scope.$on('changeParent', function(event, parentScope) { var children; children = parentScope.item.children; parentScope.item.selected = $filter('selected')(children).length === children.length; parentScope = parentScope.$parent.$parent; if (parentScope.item != null) { return $scope.$broadcast('changeParent', parentScope); } }); } ]); app.filter('selected', [ '$filter', function($filter) { return function(files) { return $filter('filter')(files, { selected: true }); }; } ]); }).call(this); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiPGFub255bW91cz4iXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7QUFBQSxNQUFBLEdBQUEsRUFBQTs7RUFBQSxJQUFBLEdBQU87SUFDSDtNQUFBLElBQUEsRUFBTSxXQUFOO01BQ0EsTUFBQSxFQUFRLElBRFI7TUFFQSxRQUFBLEVBQVU7UUFDTjtVQUFBLElBQUEsRUFBTSxXQUFOO1VBQ0EsUUFBQSxFQUFVO1lBQ047Y0FBQSxJQUFBLEVBQU0sTUFBTjtjQUNBLEtBQUEsRUFBTztZQURQLENBRE07WUFJTjtjQUFBLElBQUEsRUFBTSxNQUFOO2NBQ0EsS0FBQSxFQUFPO1lBRFAsQ0FKTTtZQU9OO2NBQUEsSUFBQSxFQUFNLE9BQU47Y0FDQSxLQUFBLEVBQU87WUFEUCxDQVBNOztRQURWLENBRE07UUFhTjtVQUFBLElBQUEsRUFBTSxVQUFOO1VBQ0EsUUFBQSxFQUFVO1lBQ047Y0FBQSxJQUFBLEVBQU0sTUFBTjtjQUNBLEtBQUEsRUFBTztZQURQLENBRE07WUFJTjtjQUFBLElBQUEsRUFBTSxNQUFOO2NBQ0EsS0FBQSxFQUFPO1lBRFAsQ0FKTTs7UUFEVixDQWJNOztJQUZWLENBREc7SUEwQkg7TUFBQSxJQUFBLEVBQU0sUUFBTjtNQUNBLFFBQUEsRUFBVTtRQUNSO1VBQUEsSUFBQSxFQUFNLFNBQU47VUFDQSxLQUFBLEVBQU87UUFEUCxDQURROztJQURWLENBMUJHO0lBZ0NIO01BQUEsSUFBQSxFQUFNLEtBQU47TUFDQSxRQUFBLEVBQVU7UUFDTjtVQUFBLElBQUEsRUFBTSxPQUFOO1VBQ0EsS0FBQSxFQUFPO1FBRFAsQ0FETTs7SUFEVixDQWhDRzs7O0VBdUNQLEdBQUEsR0FBTSxPQUFPLENBQUMsTUFBUixDQUFlLFNBQWYsRUFBMEIsRUFBMUIsQ0FBNkIsQ0FBQyxVQUE5QixDQUF5QyxXQUF6QyxFQUFzRDtJQUFFLFFBQUY7SUFBWSxTQUFaO0lBQXVCLFFBQUEsQ0FBQyxNQUFEO0lBQVMsT0FBVCxDQUFBO01BQ2pGLE1BQU0sQ0FBQyxJQUFQLEdBQWM7TUFFZCxNQUFNLENBQUMsbUJBQVAsR0FBNkIsUUFBQSxDQUFDLE1BQUQsQ0FBQTtBQUMvQixZQUFBLENBQUE7SUFBQSxJQUFBO0lBQUEsR0FBQTtJQUFBLEdBQUE7SUFBQSxPQUFBO0lBQUE7UUFBSSxRQUFBLEdBQVcsTUFBTSxDQUFDLE1BQU0sQ0FBQztBQUN6QjtBQUFBO1FBQUEsS0FBQSxxQ0FBQTs7VUFDRSxJQUFJLENBQUMsUUFBTCxHQUFnQjtVQUNoQixJQUE2QyxxQkFBN0M7eUJBQUEsTUFBTSxDQUFDLFVBQVAsQ0FBa0IsZ0JBQWxCO0lBQW9DLElBQXBDLEdBQUE7V0FBQSxNQUFBO2lDQUFBOztRQUZGLENBQUE7O01BRjJCO01BTTdCLE1BQU0sQ0FBQyxZQUFQLEdBQXNCLFFBQUEsQ0FBQyxJQUFEO0lBQU8sVUFBUCxDQUFBO2VBQ3BCLElBQUksQ0FBQyxRQUFMLEdBQWdCLFVBQUEsSUFBYyxVQUFVLENBQUMsUUFBekIsSUFBcUMsSUFBSSxDQUFDLFFBQTFDLElBQXNEO01BRGxEO01BR3RCLE1BQU0sQ0FBQyxjQUFQLEdBQXdCLFFBQUEsQ0FBQyxJQUFEO0lBQU8sV0FBUCxDQUFBO1FBQ3RCLElBQTZDLHFCQUE3QztVQUFBLE1BQU0sQ0FBQyxVQUFQLENBQWtCLGdCQUFsQjtJQUFvQyxJQUFwQyxFQUFBOztRQUNBLElBQTZDLHdCQUE3QztpQkFBQSxNQUFNLENBQUMsS0FBUCxDQUFhLGNBQWI7SUFBNkIsV0FBN0IsRUFBQTs7TUFGc0I7TUFJeEIsTUFBTSxDQUFDLEdBQVAsQ0FBVyxnQkFBWDtJQUE2QixRQUFBLENBQUMsS0FBRDtJQUFRLFVBQVIsQ0FBQTtBQUMvQixZQUFBLEtBQUE7SUFBQSxDQUFBO0lBQUEsR0FBQTtJQUFBLEdBQUE7SUFBQTtBQUFJO0FBQUE7UUFBQSxLQUFBLHFDQUFBOztVQUNFLEtBQUssQ0FBQyxRQUFOLEdBQWlCLFVBQVUsQ0FBQztVQUM1QixJQUE4QyxzQkFBOUM7eUJBQUEsTUFBTSxDQUFDLFVBQVAsQ0FBa0IsZ0JBQWxCO0lBQW9DLEtBQXBDLEdBQUE7V0FBQSxNQUFBO2lDQUFBOztRQUZGLENBQUE7O01BRDJCLENBQTdCO2FBS0EsTUFBTSxDQUFDLEdBQVAsQ0FBVyxjQUFYO0lBQTJCLFFBQUEsQ0FBQyxLQUFEO0lBQVEsV0FBUixDQUFBO0FBQzdCLFlBQUE7UUFBSSxRQUFBLEdBQVcsV0FBVyxDQUFDLElBQUksQ0FBQztRQUM1QixXQUFXLENBQUMsSUFBSSxDQUFDLFFBQWpCLEdBQTRCLE9BQUEsQ0FBUSxVQUFSLENBQUEsQ0FBb0IsUUFBcEIsQ0FBNkIsQ0FBQyxNQUE5QixLQUF3QyxRQUFRLENBQUM7UUFDN0UsV0FBQSxHQUFjLFdBQVcsQ0FBQyxPQUFPLENBQUM7UUFDbEMsSUFBa0Qsd0JBQWxEO2lCQUFBLE1BQU0sQ0FBQyxVQUFQLENBQWtCLGNBQWxCO0lBQWtDLFdBQWxDLEVBQUE7O01BSnlCLENBQTNCO0lBckJpRixDQUF2QjtHQUF0RDs7RUE0Qk4sR0FBRyxDQUFDLE1BQUosQ0FBVyxVQUFYLEVBQXVCO0lBQUMsU0FBRDtJQUFZLFFBQUEsQ0FBQyxPQUFELENBQUE7YUFDakMsUUFBQSxDQUFDLEtBQUQsQ0FBQTtlQUNFLE9BQUEsQ0FBUSxRQUFSLENBQUEsQ0FBa0IsS0FBbEI7SUFBeUI7VUFBQyxRQUFBLEVBQVU7UUFBWCxDQUF6QjtNQURGO0lBRGlDLENBQVo7R0FBdkI7QUFuRUEiLCJzb3VyY2VzQ29udGVudCI6WyJsaXN0ID0gW1xuICAgIG5hbWU6ICdEZXZlbG9wZXInXG4gICAgb3BlbmVkOiB0cnVlXG4gICAgY2hpbGRyZW46IFtcbiAgICAgICAgbmFtZTogJ0Zyb250LUVuZCdcbiAgICAgICAgY2hpbGRyZW46IFtcbiAgICAgICAgICAgIG5hbWU6ICdKYWNrJ1xuICAgICAgICAgICAgdGl0bGU6ICdMZWFkZXInXG4gICAgICAgICAgLFxuICAgICAgICAgICAgbmFtZTogJ0pvaG4nXG4gICAgICAgICAgICB0aXRsZTogJ1NlbmlvciBGMkUnXG4gICAgICAgICAgLFxuICAgICAgICAgICAgbmFtZTogJ0phc29uJ1xuICAgICAgICAgICAgdGl0bGU6ICdKdW5pb3IgRjJFJ1xuICAgICAgICBdXG4gICAgICAsXG4gICAgICAgIG5hbWU6ICdCYWNrLUVuZCdcbiAgICAgICAgY2hpbGRyZW46IFtcbiAgICAgICAgICAgIG5hbWU6ICdNYXJ5JyxcbiAgICAgICAgICAgIHRpdGxlOiAnTGVhZGVyJ1xuICAgICAgICAgICxcbiAgICAgICAgICAgIG5hbWU6ICdHYXJ5J1xuICAgICAgICAgICAgdGl0bGU6ICdJbnRlcm4nXG4gICAgICAgIF1cbiAgICBdXG4gICxcbiAgICBuYW1lOiAnRGVzaWduJ1xuICAgIGNoaWxkcmVuOiBbXG4gICAgICBuYW1lOiAnRnJlZW1hbidcbiAgICAgIHRpdGxlOiAnRGVzaWduZXInXG4gICAgXVxuICAsXG4gICAgbmFtZTogJ1MmUydcbiAgICBjaGlsZHJlbjogW1xuICAgICAgICBuYW1lOiAnTmlra3knXG4gICAgICAgIHRpdGxlOiAnUm9ib3QnXG4gICAgXVxuXVxuXG5hcHAgPSBhbmd1bGFyLm1vZHVsZSgndGVzdEFwcCcsIFtdKS5jb250cm9sbGVyKCd0cmVlVGFibGUnLCBbICckc2NvcGUnLCAnJGZpbHRlcicsICgkc2NvcGUsICRmaWx0ZXIpIC0+XG4gICRzY29wZS5saXN0ID0gbGlzdCAgXG4gIFxuICAkc2NvcGUudG9nZ2xlQWxsQ2hlY2tib3hlcyA9ICgkZXZlbnQpIC0+XG4gICAgc2VsZWN0ZWQgPSAkZXZlbnQudGFyZ2V0LmNoZWNrZWRcbiAgICBmb3IgaXRlbSBpbiAkc2NvcGUubGlzdFxuICAgICAgaXRlbS5zZWxlY3RlZCA9IHNlbGVjdGVkXG4gICAgICAkc2NvcGUuJGJyb2FkY2FzdCgnY2hhbmdlQ2hpbGRyZW4nLCBpdGVtKSBpZiBpdGVtLmNoaWxkcmVuP1xuXG4gICRzY29wZS5pbml0Q2hlY2tib3ggPSAoaXRlbSwgcGFyZW50SXRlbSkgLT5cbiAgICBpdGVtLnNlbGVjdGVkID0gcGFyZW50SXRlbSAmJiBwYXJlbnRJdGVtLnNlbGVjdGVkIHx8IGl0ZW0uc2VsZWN0ZWQgfHwgZmFsc2VcbiAgXG4gICRzY29wZS50b2dnbGVDaGVja2JveCA9IChpdGVtLCBwYXJlbnRTY29wZSkgLT5cbiAgICAkc2NvcGUuJGJyb2FkY2FzdCgnY2hhbmdlQ2hpbGRyZW4nLCBpdGVtKSBpZiBpdGVtLmNoaWxkcmVuP1xuICAgICRzY29wZS4kZW1pdCgnY2hhbmdlUGFyZW50JywgcGFyZW50U2NvcGUpIGlmIHBhcmVudFNjb3BlLml0ZW0/XG5cbiAgJHNjb3BlLiRvbiAnY2hhbmdlQ2hpbGRyZW4nLCAoZXZlbnQsIHBhcmVudEl0ZW0pIC0+XG4gICAgZm9yIGNoaWxkIGluIHBhcmVudEl0ZW0uY2hpbGRyZW5cbiAgICAgIGNoaWxkLnNlbGVjdGVkID0gcGFyZW50SXRlbS5zZWxlY3RlZFxuICAgICAgJHNjb3BlLiRicm9hZGNhc3QoJ2NoYW5nZUNoaWxkcmVuJywgY2hpbGQpIGlmIGNoaWxkLmNoaWxkcmVuP1xuXG4gICRzY29wZS4kb24gJ2NoYW5nZVBhcmVudCcsIChldmVudCwgcGFyZW50U2NvcGUpIC0+XG4gICAgY2hpbGRyZW4gPSBwYXJlbnRTY29wZS5pdGVtLmNoaWxkcmVuXG4gICAgcGFyZW50U2NvcGUuaXRlbS5zZWxlY3RlZCA9ICRmaWx0ZXIoJ3NlbGVjdGVkJykoY2hpbGRyZW4pLmxlbmd0aCA9PSBjaGlsZHJlbi5sZW5ndGhcbiAgICBwYXJlbnRTY29wZSA9IHBhcmVudFNjb3BlLiRwYXJlbnQuJHBhcmVudFxuICAgICRzY29wZS4kYnJvYWRjYXN0KCdjaGFuZ2VQYXJlbnQnLCBwYXJlbnRTY29wZSkgaWYgcGFyZW50U2NvcGUuaXRlbT9cbl0pXG5cbmFwcC5maWx0ZXIgJ3NlbGVjdGVkJywgWyckZmlsdGVyJywgKCRmaWx0ZXIpIC0+XG4gIChmaWxlcykgLT5cbiAgICAkZmlsdGVyKCdmaWx0ZXInKShmaWxlcywge3NlbGVjdGVkOiB0cnVlfSlcbl0iXX0= //# sourceURL=coffeescript
That’s all! hopefully, you have successfully integrated this AngularJS tree table with checkboxes into your project. If you have any questions or suggestions, feel free to comment below.