2016-05-17 7 views
7

I hierarchische Daten wie diese:Angular anhängen Eltern Attributwert

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

Ich mag, dass die Daten durch Abflachen baumartige Raster bauen. Ich bin mit dem folgenden Direktiven:

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

Das Problem ist, dass in der Sammlung von link Methode hinzugefügt, depth von übergeordnetem Bereich auf newDepth angehängt. Als Ergebnis hat depth für Knoten der Ebene 3 den Wert depth="3 2 1 ".

Wie zum Erben von depth deaktivieren?

Ich habe auch bemerkt, dass, wenn ich replace auf false in collection und member Richtlinien ändern, Tiefe wie vorgesehen funktioniert, aber dann ist HTML ungültig.

+0

Könnten Sie ein Plunker oder Geige für Ihren Fall zur Verfügung stellen? –

+0

@SpartakLalaj Hier sind Sie: https://plnrkr.co/edit/CE2z5WeU41H4qJQQ73B7?p=preview – Krzysztof

+0

Ich entfernte Tiefe Attribut und erklärte es mit Gleichheitszeichen in der Sammlung und scheint, dass die Zahlen korrekt sind. Probieren Sie, ob das das richtige Ergebnis ist! –

Antwort

0

Es scheint, dass die Verwendung desselben Bereichs für untergeordnete Knoten diese seltsame Verkettung verursacht. Die Heilung ist ziemlich einfach, wie sich herausstellte - für jedes Kind wird ein neuer Kindbereich benötigt. Link-Funktion wird wie folgt aussehen:

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

Ich habe auch irgendwo anders auf SO und in API gefunden, dass replace veraltet ist, also eigentlich should't es verwendet werden. Also ohne ersetzen kann wie folgt aussehen:

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

Manchmal sind viel einfachere Lösungen besser. Es ist besser, tree like Strukturen im Dienst zu glätten und dann mit ng-repeat über eine neue Struktur zu iterieren. https://plnkr.co/edit/CiFGZYi6NdH8ZFDiAyPz?p=preview

Viel einfacher Code. Es gibt keine Notwendigkeit für all diese Richtlinien, die es schwer verständlich machen. Auch sollten Sie nicht ersetzen mit Direktiven wie es deprecated ist.

Um den Stil dynamisch festzulegen, sollten Sie die Anweisung ng-style verwenden.

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

Ich kann auch dedizierte Baumkomponente verwenden, aber es ist kein Punkt. Dieses Verhalten ist meiner Meinung nach zumindest merkwürdig, und ich möchte jetzt, wenn es beabsichtigt ist (und irgendwie deaktiviert werden kann) oder wenn es ein Fehler ist. Die seltsamste Sache ist, dass, wenn ich Replace-Flag auf False umschalte, dann funktioniert es gut (aber dann Markup ist durcheinander). – Krzysztof

+0

Ich habe nicht so nah dran, aber ich wette, dass das Problem mit der Verwendung von '@' und String-Verkettung ist. übrigens. Warum hast du das so komisch gemacht? – sielakos

+0

Ich spiele nur mit eckigen, und dieses Verhalten ist nicht das, was ich erwartet habe. Da ich auf dieses Problem gestoßen bin, würde ich gerne Lösung wissen. – Krzysztof