2016-05-17 81 views
7

ho dati gerarchici come questo:angolare aggiunge genitore valore di attributo

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

voglio costruire griglia ad albero appiattendo tali dati. Sto usando seguenti direttive:

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

Il problema è che, nella collezione aggiunto da link metodo, depth dal campo di applicazione genitore è allegato al newDepth. Di conseguenza, depth per i nodi di livello 3 ha valore depth="3 2 1 ".

Come disabilitare l'ereditarietà di depth?

Ho anche notato che quando cambio in false in collection e member, la profondità funziona come previsto, ma HTML non è valido.

+0

Potrebbe fornire un plunker o violino per il vostro caso? –

+0

@SpartakLalaj Eccovi: https://plnkr.co/edit/CE2z5WeU41H4qJQQ73B7?p=preview – Krzysztof

+0

Ho rimosso l'attributo depth e l'ho dichiarato con il segno di uguale nella raccolta e sembra che i numeri siano corretti. Prova a vedere se questo è il risultato corretto! –

risposta

0

Sembra, che utilizzando la stessa possibilità di nodi figlio, fa sì che la concatenazione strano. Curare questo è piuttosto semplice, come si è scoperto - per ogni bambino è richiesto un nuovo ambito figlio. funzione di collegamento sarà simile a questa:

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

Ho anche trovato qualche altra parte sul SO e API, che replace è deprecato, quindi in realtà si should't essere utilizzato. Quindi, senza sostituirlo potrebbe essere questa:

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

A volte soluzioni molto più semplici sono migliori. È meglio appiattire strutture simili ad albero in servizio e poi scorrere su nuove strutture usando ng-repeat. https://plnkr.co/edit/CiFGZYi6NdH8ZFDiAyPz?p=preview

Codice molto più semplice. Non c'è bisogno di tutte quelle direttive che rendono difficile capire. Inoltre, non utilizzare la sostituzione con le direttive poiché è deprecated.

Per impostare lo stile in modo dinamico, è necessario utilizzare la direttiva 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

Posso anche usare il componente ad albero dedicato, ma non è un punto. Questo comportamento è per lo meno strano a mio avviso, e vorrei ora se è inteso (e può essere disabilitato in qualche modo) o se è un bug. La cosa più strana è che quando cambio il flag replace su false, allora funziona bene (ma poi il markup è incasinato). – Krzysztof

+0

Non l'ho visto così vicino, ma scommetto che il problema è con l'uso di "@" e la concatenazione di stringhe. btw. Perché l'hai fatto in un modo così strano? – sielakos

+0

Sto solo giocando con l'angolare, e quel comportamento non è quello che mi aspettavo. Dal momento che mi sono imbattuto in quel problema mi piacerebbe sapere la soluzione. – Krzysztof