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.
