2013-08-11 8 views
9

Sto provando a creare una vista ad albero utilizzando AngularJS.Direttive personalizzate ricorsive con ngRepeat

Ecco il mio codice:

module.directive('treeview', function() { 
    return { 
     restrict: 'E', 
     templateUrl: "/templates/ui/controls/treeview.htm", 
     replace: true, 
     transclude: true, 
     scope: {}, 
     link: function (scope, element, attrs) { 
      console.log("treeview directive loaded"); 
     }, 
     controller: function ($scope, $rootScope) { 
      $rootScope.depth = 0; 
      $scope.items = [ 
       { text: "face" }, 
       { text: "palm" }, 
       { 
        text: "cake", 
        childitems: [ 
         { text: "1 face" }, 
         { text: "1 palm" }, 
         { text: "1 cake" } 
        ] 
       } 
      ]; 
     } 
    }; 
}); 

module.directive('treeviewItem', function() { 
    return { 
     restrict: 'E', 
     templateUrl: "/templates/ui/controls/treeview-item.htm", 
     replace: true, 
     scope: { 
      item: "=" 
     }, 
     link: function (scope, element, attrs) { 
      console.log("treeview item directive loaded"); 
     } 
    }; 
}); 

modello Treeview:

<div class="sl-treeview"> 
    <ul class="clear" ng-transclude> 
     <treeview-item ng-repeat="item in items" item="item"></treeview-item> 
    </ul> 
</div> 

Treeview modello dell'oggetto:

<li> 
    <i class="icon-plus-sign"></i> 
    <a href="/"> 
     <i class="icon-folder-close"></i> 
     {{item.text}} 
    </a> 
    <!-- This ul is the issue - it crashes the page --> 
    <ul> 
     <treeview-item ng-repeat="childitem in item.childitems" item="childitem"></treeview-item> 
    </ul> 
</li> 

Nella direttiva TreeView $scope.items è codificato per lo sviluppo - alla fine spero che questo verrà da un controller/servizio che preleva i dati dal servizio r. Tuttavia rappresenta il tipo di struttura di base che sto cercando.

Quando eseguo questo senza l'ul annidato in treeviewItem, mi danno i primi tre elementi. Quando aggiungo l'ul in per cercare di ottenere i controlli da associare agli elementi figlio, passa la pagina e smette di funzionare.

JSFiddle senza ul nested - lavoro: - (! E può appendere il browser)

http://jsfiddle.net/BdmV3/

JSFiddle con ul nidificato non funziona:

http://jsfiddle.net/SKPpv/

Come devo fare per fare un controllo che usa una direttiva personalizzata e ngRepeat per creare livelli potenzialmente infiniti di ricorsione? Perché il mio approccio non funziona?

risposta

15

Il problema è che si sta cercando di definire la direttiva in modo ricorsivo, quando angolare stava cercando di compilare il modello, ha visto treeview direttiva, si chiama treeview 's funzione di compilare, allora vide treeviewItem direttiva, si chiama treeviewItem' s compilare la funzione, allora vide treeviewItem direttiva, si chiama treeviewItem 's funzione compile, allora vide treeviewItem direttiva, si chiama treeviewItem' s compilare funzione ...

vedere il problema? Le chiamate per compilare le funzioni non potevano fermarsi. Quindi, è necessario tirare la definizione ricorsiva del vostro template, ma utilizzare $compile per costruire DOM manualmente:

module.directive('treeviewItem', function ($compile) { 
    return { 
     restrict: 'E', 
     template: '<li><i class="icon-plus-sign"></i><a href="/"><i class="icon-folder-close"></i>{{item.text}}</a></li>', 
     replace: true, 
     scope: { 
      item: "=" 
     }, 
     link: function (scope, element, attrs) { 
      element.append($compile('<ul><treeview-item ng-repeat="childitem in item.childitems" item="childitem"></treeview-item></ul>')(scope)); 

      console.log("treeview item directive loaded"); 
     } 
    }; 
}); 

http://jsfiddle.net/SKPpv/3/

In alternativa, ho trovato una soluzione per visualizzare i dati ad albero su SO https://stackoverflow.com/a/11861030/69172. La soluzione tuttavia utilizza ngInclude anziché le direttive.

+0

Mi sono imbattuto in $ compilazione guardando altri esempi di visualizzazioni di tre e quella era l'opzione che ho preso. Funziona magnificamente. Che tu per la spiegazione del perché il mio approccio originale non funziona, è ovvio ora! Di interesse, perché stai guardando 'item.childitems'? Non aggiungerà un ul per ogni articolo figlio? – Jon

+0

@Jon Non dovrei usare '$ watch' come nella mia risposta originale, sarà semplice aggiungere un altro' ul' ogni volta che 'childitems' cambia. Ho aggiornato la mia risposta senza usare '$ watch'. Inoltre, puoi condividere l'esempio di treeview che hai trovato nella tua domanda in modo che tutti possano beneficiare maggiormente della tua domanda? –

+0

Questo non funziona più nelle versioni più recenti di angular (> 1.2) –