Reputation: 28328
I have a tree structure which requires a different set of styling for each level in three tree. Therefore I need some way of keeping track of which level an item is in, so I thought that if there is some way to set a unique ID for an ng-repeat
(NOT the items inside) dynamically, I could easily perform some maths to give the correct stylings inline.
Now I got a recursive tree structure using three files; a wrapper, a new level and a branch (which is the same as a new level). treeWrapper
and treeLevel
is directive which uses these templates.
I've performed an ng-include
inside the tree-branch.html
file in order to make it recursive. The first ng-include
inside tree-level.html
is just to "kickstart" the recursiveness.
So my question is simply how to set an id for each ng-repeat
in the tree? Is this even possible?
tree-wrapper.html
:
<div class="tree-wrapper">
<tree-level ctrl="ctrl" tree="tree"></tree-level>
</div>
tree-level.html
:
<ul class="tree-list">
<li class="tree-item" ng-repeat="branch in tree track by $index"
ng-include="'/app/views/components/tree/tree-branch.html'"></li>
</ul>
tree-branch.html
:
<div ng-click="ctrl.toggleBranch(branch)" ng-bind="branch.name"></div>
<ul class="tree-list" ng-if="branch.branches">
<li class="tree-item" style="padding-left: {{$index * 5}}" ng-repeat="branch in branch.branches"
ng-include="'/app/views/components/tree/tree-branch.html'"></li>
</ul>
Upvotes: 1
Views: 972
Reputation: 17048
This can be easily done by using directives instead of inclusion.
A tree-branch template will looks like this:
<ul class="branch-level-{{vm.level}}">
<li ng-repeat="branch in vm.branch.branches">
<tree-branch level="vm.level + 1" branch="branch"></tree-branch>
</li>
</ul>
And the directive definition looks like
{
scope : {
level : '=',
branch : '='
}
}
The kickstart in tree-level.html
can be simplify:
<tree-branch level="0" branch="tree"></tree-branch>
Note that recursion with directives will blow up the compiler, you have to handle it yourself. See this post to know how to do it: Recursion in Angular directives
/*
* An Angular service which helps with creating recursive directives.
* @author Mark Lagendijk
* @license MIT
*/
angular.module('RecursionHelper', []).factory('RecursionHelper', ['$compile',
function($compile) {
return {
/**
* Manually compiles the element, fixing the recursion loop.
* @param element
* @param [link] A post-link function, or an object with function(s) registered via pre and post properties.
* @returns An object containing the linking functions.
*/
compile: function(element, link) {
// Normalize the link parameter
if (angular.isFunction(link)) {
link = {
post: link
};
}
// Break the recursion loop by removing the contents
var contents = element.contents().remove();
var compiledContents;
return {
pre: (link && link.pre) ? link.pre : null,
/**
* Compiles and re-adds the contents
*/
post: function(scope, element) {
// Compile the contents
if (!compiledContents) {
compiledContents = $compile(contents);
}
// Re-add the compiled contents to the element
compiledContents(scope, function(clone) {
element.append(clone);
});
// Call the post-linking function, if any
if (link && link.post) {
link.post.apply(null, arguments);
}
}
};
}
};
}
]);
angular.module('recursionDemo', ['RecursionHelper'])
.controller("TreeController", function($scope) {
$scope.treeFamily = {
name: "Parent",
children: [{
name: "Child1",
children: [{
name: "Grandchild1",
children: []
}, {
name: "Grandchild2",
children: [{
name: "GrandGrandchild1",
children: []
}]
}, {
name: "Grandchild3",
children: []
}]
}, {
name: "Child2",
children: []
}]
};
})
.directive("tree", function(RecursionHelper) {
return {
restrict: "E",
scope: {},
bindToController: {
family: '=',
level: '='
},
controller: function() {},
controllerAs: 'vm',
template: '{{vm.family.name}} Level = {{vm.level}} ' +
'<ul>' +
' <li ng-repeat="child in vm.family.children">' +
' <tree family="child" level="vm.level+1"></tree>' +
' </li>' +
'</ul>',
compile: function(element) {
return RecursionHelper.compile(element, function(scope, iElement, iAttrs, controller, transcludeFn) {
// Define your normal link function here.
// Alternative: instead of passing a function,
// you can also pass an object with
// a 'pre'- and 'post'-link function.
});
}
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<div ng-app="recursionDemo" ng-controller="TreeController">
<tree family="treeFamily" level="0"></tree>
</div>
Upvotes: 2