Angular adds parent attribute value

I have hierarchical data:

[ { "children":[ { "children":[...], [...] }, { "children":[...], [...] }, ], [...] } ] 

I want to build a tree grid by smoothing this data. I use the following directives:

 app.directive('tree', function (hierarchyService, logger, $timeout) { return { scope: { data: '=' }, restrict: 'E', replace: true, template: '<div>' + '<table class="table table-striped table-hover">' + ' <thead>' + ' <tr>' + ' <th class="col-md-6">Account name</th>' + ' </tr>' + ' </thead>' + ' <tbody><tr collection data="data" /></tbody>' + ' </table>' + '</div>' }; }); app.directive('collection', function() { return { restrict: "A", replace: true, scope: { data: '=', depth: '@' }, template: '<member ng-repeat="member in data" member="member" depth="{{depth}}" />', link: function (scope, element, attrs) { scope.depth = parseInt(scope.depth || 0); } } }); app.directive('member', function($compile) { return { restrict: "E", replace: true, scope: { depth: '@', member: '=' }, template: '<tr ng-class="{selected: member.selected}">' + '<td>' + ' <span ng-show="depth > 0" style="width: {{depth * 16}}px; display: inline-block;"></span> {{member.name}}' + '</td>' + '</tr>', link: function (scope, element, attrs) { scope.depth = parseInt(scope.depth || 0); if (angular.isArray(scope.member.children) && scope.member.children.length > 0) { var el = angular.element('<tr collection data="member.children" depth="{{newDepth}}" />'); scope.depth = parseInt(scope.depth || 0); scope.newDepth = scope.depth + 1; $compile(el)(scope); // Flatten hierarchy, by appending el to parent element.parent().append(el); } } } }); 

The problem is that in the collection added from the link method, depth from the parent area is added to newDepth . As a result, depth for level 3 nodes has the value depth="3 2 1 " .

How to disable depth inheritance?

I also noticed that when I change replace to false in the collection and member directives, the depth works as intended, but then the HTML is invalid.

+7
javascript angularjs angularjs-directive hierarchy
source share
2 answers

It seems that using the same scope for child nodes causes this strange concatenation. It is quite simple to cure, as it turned out: for each child a new coverage of the child is required. The Link function will look like this:

 link: function (scope, element, attrs) { if (angular.isArray(scope.member.children) && scope.member.children.length > 0) { // Create isolated child scope, pass `scope` as parent var childScope = scope.$new(true, scope); childScope.depth = parseInt(scope.depth || 0) + 1; childScope.member = scope.member; var el = angular.element('<tr collection data="member.children" depth="{{depth}}" />'); // use child scope $compile(el)(childScope); // Flatten hierarchy, by appending el to parent element.after(el); } } 

Plunk: https://plnkr.co/edit/xhJwfV?p=preview

I also found somewhere else on SO and in the API that replace deprecated, so it should not really be used. Therefore, without replacement, it may look like this:

 app.directive('tree', function () { return { restrict: 'E', template: '<div>' + '<table class="table table-striped table-hover">' + ' <thead>' + ' <tr>' + ' <th class="col-md-6">Account name</th>' + ' <th class="col-md-1">Depth</th>' + ' </tr>' + ' </thead>' + ' <tbody row data="data"></tbody>' + ' </table>' + '</div>', link: function (scope, element, attrs) { scope.data = [ { name: 'Root', children: [ { name: 'Level 1', children: [ { name: 'Level 2', children: [ {name: "Level 3"}, {name: "Level 3 -1"} ] } ] }, { "name": "Level 1-1" } ] } ]; } }; }); app.directive('row', function() { return { restrict: "A", scope: { data: '=', depth: '@' }, template: '<tr cells ng-repeat="member in data" member="member" />', link: function (scope, element, attrs) { scope.depth = parseInt(scope.depth || 0); } } }); app.directive('cells', function($compile) { return { restrict: "A", scope: { data: '=', depth: '@', member: '=' }, template: //'<tr ng-class="{selected: member.selected}">' + '<td>' + ' <span ng-show="depth > 0" style="width: {{depth * 16}}px; display: inline-block;"></span> {{member.name}}' + '</td>' + '<td>{{depth}}</td>', //'</tr>', link: function (scope, element, attrs) { if (scope.member && angular.isArray(scope.member.children) && scope.member.children.length > 0) { var childScope = scope.$new(true); childScope.depth = parseInt(scope.depth || 0) + 1; childScope.data = scope.member.children; var el = angular.element('<tr cells ng-repeat="member in data" member="member" depth="{{depth}}" />'); $compile(el)(childScope); // Flatten hierarchy, by appending el to parent element.after(el); } } } }); 

Plunker: https://plnkr.co/edit/j3YcuQ?p=preview

0
source share

Sometimes much simpler solutions are better. It is better to smooth the tree, as the structures are in maintenance, and then iterate over the new structure using ng-repeat. https://plnkr.co/edit/CiFGZYi6NdH8ZFDiAyPz?p=preview

More simple code. There is no need for all of these directives, which make it difficult to understand. Also you should not use replace with directives since it is deprecated .

To dynamically set a style, you must use the ng-style directive.

 var app = angular.module('app', []); app.factory('treeFlatting', function () { function flattenTree(tree, depth) { depth = depth || 0; return tree.reduce(function (rows, node) { var row = { name: node.name, depth: depth, }; var childrenRows = angular.isArray(node.children) ? flattenTree(node.children, depth + 1) : []; return rows.concat(row, childrenRows); }, []); } return flattenTree; }); app.directive('tree', function (treeFlatting) { return { restrict: 'E', replace: true, template: '<div>' + '<table class="table table-striped table-hover">' + ' <thead>' + ' <tr>' + ' <th class="col-md-6">Account name</th>' + ' <th class="col-md-1">Depth</th>' + ' </tr>' + ' </thead>' + ' <tbody>'+ ' <tr ng-repeat="row in rows">'+ ' <td ng-style="{\'padding-left\': (16 * row.depth) + \'px\'}">{{row.name}}</td>'+ ' <td>{{row.depth}}</td>'+ ' </tr>'+ ' </tbody>' + ' </table>' + '</div>', link: function (scope, element, attrs) { scope.data = [ { name: 'Root', children: [ { name: 'Level 1', children: [ { name: 'Level 2' } ] } ] } ]; scope.rows = treeFlatting(scope.data).filter(function (row) { return row.depth > 0; }); } }; }); 
+2
source share

All Articles