2015-08-18 7 views
10

Ich habe eine Direktive an ein dynamisch generiertes <table> Element in einer Vorlage angehängt. Die Direktive manipuliert das DOM dieser Tabelle innerhalb einer link-Funktion. Das Problem besteht darin, dass die Anweisung ausgeführt wird, bevor die Tabelle gerendert wird (durch Auswertung der ng-repeat-Anweisungen) - die Tabelle ist dann leer.Die AngularJS-Anweisung wird ausgeführt, bevor das Element vollständig geladen ist

Frage

Wie kann ich sicherstellen, dass die Richtlinie läuft, nachdem der Tisch vollständig erbracht wurde?

<table directive-name> 
    <tr ng-repeat="..."> 
     <td ng-repeat="..."></td> 
    </tr> 
</table> 


module.directive("directiveName", function() { 
    return { 
     scope: "A", 
     link: function(scope, element, attributes) { 
      /* I need to be sure that the table is already fully 
       rendered when this code runs */ 
     } 
    }; 
}); 
+1

Sie können ng-wenn in der Tabelle Tag und Bedingung kann sein, wenn Tabellendaten geladen werden – Hmahwish

+0

ist Ihre Daten kommen von '$ http' Anfrage oder nur hart codierte Daten –

+0

@K.Toress Data kommt von einer HTTP-Anfrage, aber sie wird bereits geladen, wenn diese Vorlage verarbeitet wird - Routing und Controller kümmern sich darum, indem sie das 'resolve' Attribut in der' $ routeProvider' Konfiguration benutzen. –

Antwort

4

Sie können im allgemeinen Sinne niemals "völlig sicher" sein, indem Sie einfach eine Direktive zum <table> Element haben.

Aber Sie können in bestimmten Fällen sicher sein. Wenn in Ihrem Fall der innere Inhalt ng-repeat -ed ist, dann sind die tatsächlichen DOM-Elemente am Ende des Digest-Zyklus bereit, wenn das Array von Elementen, über das ngRepeat arbeitet, bereit ist. Sie können es erfassen nach $timeout mit 0 Verzögerung:

link: function(scope, element){ 
    $timeout(function(){ 
    console.log(element.find("tr").length); // will be > 0 
    }) 
} 

Aber in einem allgemeinen Sinne, können Sie nicht sicher sein, um den Inhalt zu erfassen. Was ist, wenn das ngRepeat Ed-Array noch nicht da ist? Oder was, wenn es stattdessen eine ng-include gibt?

<table directive-name ng-include="'templates/tr.html'"> 
</table> 

Oder was, wenn es eine benutzerdefinierte Richtlinie war, die anders gearbeitet als ngRepeat tut?

Aber wenn Sie die volle Kontrolle über die Inhalte haben, eine Möglichkeit zu wissen, ist, einige Helfer Richtlinie als innerste/letzte Element aufzunehmen, und haben sie ihre Mutter directiveName kontaktieren, wenn es verknüpft ist:

<table directive-name> 
    <tr ng-repeat="..."> 
     <td ng-repeat="..."> 
      <directive-name-helper ng-if="$last"> 
     </td> 
    </tr> 
</table> 
.directive("directiveNameHelper", function(){ 
    return { 
    require: "?^directiveName", 
    link: function(scope, element, attrs, ctrl){ 
     if (!ctrl) return; 

     ctrl.notifyDone(); 
    } 
    } 
}) 
+2

Das ist die umfassendste Antwort hier, denke ich. Vielen Dank. Ich verstehe immer noch nicht, warum '$ timeout' mit 0 Delay garantiert, dass DOM bereit sein wird, aber ich denke, ich werde das in Angulas '$ timeout'-Dokumenten finden. –

+1

@Robert, 'ng-repeat' hat einen' $ scope. $ WatchCollection' - dies wird nach der Link-Phase ausgelöst, und wenn das Array bereit ist, dann wird die 'ng-repeat'-ed-Vorlage in die DOM. '$ timeout' mit 0 Verzögerung wird direkt danach ausgeführt. –

2

Versuchen Verpackung in einem $timeout den Code von Ihrer Link-Funktion, wie es wird ausgeführt, nachdem das DOM gerendert wird.

$timeout(function() { 
    //do your stuff here as the DOM has finished rendering already 
}); 

Vergessen Sie nicht $timeout in Ihrer Richtlinie zu injizieren:

.directive("directiveName", function($timeout) { 

Es gibt viele Alternativen, aber ich denke, das ist ein sauberer ist als die $ timeout, nachdem der Motor seine Arbeit beendet hat, Rendering ausführt .

0

Ein sauberer Weg wäre, etwas wie lodash's _.defer method zu verwenden.

Sie können es mit _.defer(your_func, your_func_arg1, your_func_arg2, ...) in Ihrem Link aufrufen, um die Methode auszuführen, wenn der aktuelle Aufrufstapel gelöscht und alles bereit ist.

Auf diese Weise müssen Sie $timeout nicht selbst schätzen.

+0

' _defer' ruft 'setTimout' ohne Verzögerung auf, obwohl es einige Laufzeitüberprüfungen der Parameter durchführt, die Sie übergeben. Wenn Sie nicht bereits lodash verwenden, werden Sie könnte auch NG's eingebauten $ Timeout ohne Verzögerung verwenden. – jusopi

+0

Wusste das nicht, danke! –

Verwandte Themen