Angular附加父属性值

时间:2016-05-17 07:56:28

标签: javascript angularjs angularjs-directive hierarchy

我有这样的分层数据:

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

我希望通过展平数据来构建树状网格。我使用以下指令:

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);
            }
        }
    }
});

问题是,在从link方法添加的集合中,来自父作用域的depth会附加到newDepth。因此,级别3节点的depth值为depth="3 2 1 "

如何禁用继承depth

我还注意到,当我在replacecollection指令中将member更改为false时,深度按预期工作,但HTML无效。

2 个答案:

答案 0 :(得分:2)

有时候,更简单的解决方案会更好。最好在服务中压扁树状结构,然后使用ng-repeat迭代新结构。 https://plnkr.co/edit/CiFGZYi6NdH8ZFDiAyPz?p=preview

更简单的代码。所有这些指令都不需要让人难以理解。此外,您不应该使用替换指令,因为它是deprecated

要动态设置样式,您应该使用ng-style指令。

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;
          });
        }
    };
});

答案 1 :(得分:0)

看起来,对子节点使用相同的范围会导致奇怪的连接。事实证明,这很简单,每个孩子都需要新的孩子范围。链接功能如下所示:

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);
    }
}

普兰克:https://plnkr.co/edit/xhJwfV?p=preview

我还在SO和API中找到了其他地方,replace已被弃用,所以实际上它不应该被使用。所以没有替换它可以看起来像这样:

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