2016-05-17 2 views
7

У меня есть иерархические данные, как это:Угловые присоединяет значение атрибута родительского

[ 
    { 
     "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. В результате depth для узлов уровня 3 имеет значение depth="3 2 1 ".

Как отключить наследование depth?

Я также заметил, что когда я изменяю replace на false в collection и member директивы, глубина работает по назначению, но тогда HTML недействителен.

+0

могли бы вы предоставить plunker или скрипку для вашего дела? –

+0

@SpartakLalaj Вот вы: https://plnkr.co/edit/CE2z5WeU41H4qJQQ73B7?p=preview – Krzysztof

+0

Я удалил атрибут глубины и объявил его с равным знаком в коллекции, и кажется, что цифры верны. Попробуйте и убедитесь, что это правильный результат! –

ответ

0

Кажется, что использование той же области для дочерних узлов вызывает эту странную конкатенацию. Вылечить это довольно просто, как оказалось: для каждого ребенка требуется новый охват ребенка. Функция Link будет выглядеть следующим образом:

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

Я также нашел где-то еще на SO и API, что replace является устаревшим, поэтому на самом деле это should't использовать. Так что без его замены может выглядеть следующим образом:

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

2

Иногда гораздо более простые решения лучше. Лучше сгладить дерево, как структуры в обслуживании, а затем перебрать новую структуру, используя ng-repeat. https://plnkr.co/edit/CiFGZYi6NdH8ZFDiAyPz?p=preview

Более простой код. Нет необходимости в всех этих директивах, которые затрудняют понимание. Также не следует использовать директивы replace, как это указано 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; 
      }); 
     } 
    }; 
}); 
+0

Я также могу использовать выделенный древовидный компонент, но это не вопрос. На мой взгляд, это по крайней мере странно, и я хотел бы сейчас, если он предназначен (и может быть каким-то образом отключен), или если это ошибка. Самое странное, что когда я заменяю флаг replace на false, он работает нормально (но тогда разметка запущена). – Krzysztof

+0

Я не выгляжу так близко, но я уверен, что проблема связана с использованием «@» и конкатенации строк. Кстати. Почему вы так поступили так странно? – sielakos

+0

Я просто играю с угловатым, и это поведение не то, что я ожидал. Поскольку я столкнулся с этой проблемой, я хотел бы знать решение. – Krzysztof

Смежные вопросы