2014-06-09 9 views
6

Ho provato a creare la mia direttiva ricorsiva con AngularJS, che si chiama per trasformare un oggetto in una vista con un bel formato JSON. Bene, per prima cosa ho usato un ng-include che chiamava uno script con il modello, con un ng-se al suo interno verificando se il valore corrente fosse un oggetto, se così fosse, la chiamata al modello stessa.

Penso sempre che questo sia un modo ungly per farlo, quindi mi trasformo in una direttiva, molto più semplice.

Sempre di più ... Perché scopro il mondo delle direttive ricorsive e ho trovato molte cose e più interessanti. Ho anche dato una lettura nel codice sorgente di Angular in github (ti consiglio di leggere: https://github.com/angular/angular.js), con era una buona cosa.

Ho cercato così duramente, e penso che sto quasi trovando l'awser che adorerà il mio cuore! Perché imparo molte nuove cose e voi ragazzi, mi aiuterete.

Guarda il mio codice nel link qui sotto: https://github.com/Daymannovaes/htmljs/blob/master/js/directives/recursiveDataTemplateDirective.js

mia direttiva sono: ricorsiva-data-template = "data", in cui i dati sono un oggetto. Questa direttiva eseguirà un loop sulla chiave e sui valori di questo oggetto e, se il valore fosse un oggetto, lo farà di nuovo. Le condizioni sono fatte con ng-if = "isObject (valore)".

Ok, il mio primo problema era il ciclo infinito. Devo rimuovere il contenuto nella fase di compilazione e quindi compilare imperativamente il contenuto nella fase postLink. La mia domanda: ** Perché la compilazione manuale non cade sullo stesso problema del ciclo infinito? **

Sto compilando lo stesso contenuto, nessuna condizione è stata creata (se if (! CompiledContent) è stata rimossa, il ciclo infinito non si verifica ancora), la differenza (credo) sono solo in malafede posto, ma non ero in grado di trovare in internet qualcuno che la mia domanda terribile!

Quindi, grazie! (se il link non funzionante, ecco il codice importante):

compile: function(templateElement, templateAttributes) { 
      /* 
       in compile time, we need to remove the innerHTML of template(url) because of its recursive. 
       Because of its recusiveness, when the $compile start to read the DOM tree and find a 
       recursiveDataTemplate directive (even its not will be evaluated all time by link function 
       because the ng-if, whatever) its start the do all the process again. So, we need the .remove() 
      */ 
      var templateDirectiveContent = templateElement.contents().remove(); 
      var compiledContent; 

      return function($scope, linkElement, linkAttributes) { 

       /* 
        This verification avoid to compile the content to all siblings, because 
        when you compile the siblings, don't work (I don't know why, yet). 
        So, doing this we get only the top level link function (from each iteration) 
       */ 
       if(!compiledContent) { 
        compiledContent = $compile(templateDirectiveContent); 
       } 

       /* 
        Calling the link function passing the actual scope we get a clone object 
        wich contains the finish viewed object, the view itself, the DOM!! 
        Then, we attach the new dom in the element wich contains the directive 
       */ 
       compiledContent($scope, function(clone) { 
        linkElement.append(clone); 
       }); 
      }; 
     }, 
    } 
<ul> 
    <li data-ng-repeat="(key, value) in fields"> 
     <span data-ng-if="!isNumber(key)"> 
      {{key}}: 
     </span> 

     <span data-ng-if="isObject(value)" recursive-data-template="value"></span> 

     <span data-ng-if="!isObject(value)"> 
      {{value}} 
     </span> 

    </li> 
</ul> 
+0

Dai un'occhiata alla: https://github.com/dotJEM/angular-tree, io personalmente non credo che la vostra idea iniziale di ricorsiva ng-include sono un tale cattiva idea, tieni presente che puoi estrapolare quell'idea a un insieme di direttive, che è esattamente ciò che fa l'albero-punto-punto-ad-albero. Penso che sia logico avere una coppia di direttive, una che definisce un punto di partenza, quindi una che si collega in modo ricorsivo, in quanto ciò ti permetterà di fare dell'albero nell'albero, senza che siano in conflitto tra loro. http://plnkr.co/edit/uaZVzUhPsDIsx93kzXSP?p=preview – Jens

+1

Questa è una domanda molto buona e mi dispiace che non sia stata fornita una buona risposta. – erilem

+0

Ero di fronte allo stesso problema e lo risolvo usando il suggerimento 'compiledContent'. Inoltre, non capisco davvero perché, mi piacerebbe che spiegazioni ufficiali accurate su tutte queste cose funzionassero. – floribon

risposta

1

Credo che questo estratto dal official documentation è importante per quello che stai chiedendo:

Nota: La funzione di compilazione non può gestire le direttive che ricorrono in modo ricorsivo in t eredi propri modelli o funzioni di compilazione. La compilazione di queste direttive comporta un ciclo infinito e errori di overflow dello stack. Ciò può essere evitato manualmente utilizzando $compile nella funzione postLink per compilare imperativamente un modello di direttiva anziché fare affidamento sulla compilazione automatica dei modelli tramite la dichiarazione template o templateUrl o la compilazione manuale all'interno della funzione di compilazione.

E andando dal codice che ci hai fornito, hai sembrano aver fatto ciò che questa nota sta suggerendo - cioè, la compilazione manualmente all'interno della funzione (postLink) stai tornando per la compile proprietà della vostra direttiva.

+0

Ok, l'ho letto. Ma questa è la mia domanda, perché la compilazione all'interno di PostLink non attiva anche un loop infinito? Sto compilando l'intero templateUrl, che contiene se stesso. – daymannovaes

+0

È interessante sapere che i documenti ufficiali hanno una nota sull'utilizzo di $ compile nella funzione post link ma che non risponde alla domanda effettiva di daymannovaes. – erilem

0

Circa il motivo per cui la compilazione durante la postLink piuttosto che la fase compile evita la ricorsione infinita, è perché tutti gli elementi del DOM sono compilati wether essi siano effettivamente utilizzati o meno, mentre il link vengono attivate solo quando l'elemento è in realtà collegato: per l'istanza se un valore più alto di ng-if è falsy, il suo elemento figli non sarà precablato, e quindi neithr postLinked ... Almeno dalla mia comprensione!

Consiglio questo buon articolo: http://www.jvandemo.com/the-nitty-gritty-of-compile-and-link-functions-inside-angularjs-directives/