Was ich zu implementieren versuche, ist im Grunde ein Handler, der das Rendern beendet. Ich kann erkennen, wann es fertig ist, aber ich kann nicht herausfinden, wie ich eine Funktion daraus auslösen kann.
Überprüfen Sie die Geige: http://jsfiddle.net/paulocoelho/BsMqq/3/
JS
var module = angular.module('testApp', [])
.directive('onFinishRender', function () {
return {
restrict: 'A',
link: function (scope, element, attr) {
if (scope.$last === true) {
element.ready(function () {
console.log("calling:"+attr.onFinishRender);
// CALL TEST HERE!
});
}
}
}
});
function myC($scope) {
$scope.ta = [1, 2, 3, 4, 5, 6];
function test() {
console.log("test executed");
}
}
HTML
<div ng-app="testApp" ng-controller="myC">
<p ng-repeat="t in ta" on-finish-render="test()">{{t}}</p>
</div>
Antwort : Working Fiddle von FinishingMove: http://jsfiddle.net/paulocoelho/BsMqq/4/
element.ready()
Snippets? Ich meine ... ist es eine Art jQuery-Plugin, das Sie haben, oder sollte es ausgelöst werden, wenn das Element bereit ist?Antworten:
Beachten Sie, dass ich es nicht verwendet
.ready()
, sondern in a eingewickelt habe$timeout
.$timeout
stellt sicher, dass es ausgeführt wird, wenn die ng-wiederholten Elemente das Rendern WIRKLICH beendet haben (da das$timeout
am Ende des aktuellen Digest-Zyklus ausgeführt wird - und im$apply
Gegensatz dazu auch intern aufgerufen wirdsetTimeout
). Nachdem dasng-repeat
beendet ist,$emit
senden wir ein Ereignis an äußere Bereiche (Geschwister- und übergeordnete Bereiche).Und dann können Sie es in Ihrem Controller abfangen mit
$on
:Mit HTML sieht das ungefähr so aus:
quelle
$timeout
(was im GrundesetTimeout
+ Angulars ist$scope.$apply()
) mitsetInterval
.$timeout
wird nur einmal proif
Bedingung ausgeführt, und das wird am Anfang des nächsten$digest
Zyklus sein. Weitere Informationen zu JavaScript-Zeitüberschreitungen finden Sie unter: ejohn.org/blog/how-javascript-timers-worksetTimeout()
mit 0 Verzögerung verwenden würden, ist eine andere Frage, obwohl ich sagen muss, dass ich nirgendwo eine tatsächliche Spezifikation für die Ereigniswarteschlange des Browsers gefunden habe, nur was durch Single-Threading und die Existenz von impliziert wirdsetTimeout()
.on-finish-render="ngRepeatFinished"
? Wenn ich zuweiseon-finish-render="helloworld"
, funktioniert es genauso.Verwenden Sie $ evalAsync, wenn Ihr Rückruf (dh test ()) ausgeführt werden soll, nachdem das DOM erstellt wurde, aber bevor der Browser gerendert wird. Dies verhindert ein Flimmern - ref .
Geige .
Wenn Sie Ihren Rückruf nach dem Rendern wirklich aufrufen möchten, verwenden Sie $ timeout:
Ich bevorzuge $ eval anstelle eines Ereignisses. Bei einem Ereignis müssen wir den Namen des Ereignisses kennen und unserem Controller Code für dieses Ereignis hinzufügen. Mit $ eval besteht weniger Kopplung zwischen dem Controller und der Direktive.
quelle
$last
? Kann es nicht in den Dokumenten finden. Wurde es entfernt?$last
wird im Bereich definiert, wenn einng-repeat
im Element aktiv ist.$timeout
.Die bisher gegebenen Antworten funktionieren nur beim ersten
ng-repeat
Rendern . Wenn Sie jedoch eine Dynamik habenng-repeat
, bedeutet dies, dass Sie Elemente hinzufügen / löschen / filtern, und Sie müssen jedes Mal benachrichtigt werden, wenn dieng-repeat
Wird gerendert, funktionieren diese Lösungen nicht für Sie.Also, wenn Sie JEDES MAL benachrichtigt werden müssen , dass die
ng-repeat
bekommt erneut gerendert und nicht nur das erste Mal habe ich einen Weg gefunden , das zu tun, es ist ziemlich ‚Hacky‘, aber es wird gut funktionieren , wenn Sie wissen , was Sie sind tun. Verwenden Sie dies$filter
in Ihrem,ng-repeat
bevor Sie andere verwenden$filter
:Dies ist
$emit
ein Ereignis, dasngRepeatFinished
jedes Mal aufgerufen wird, wenn dasng-repeat
gerendert wird.Wie man es benutzt:
Der
ngRepeatFinish
Filter muss direkt auf einenArray
oder einenObject
in Ihrem definierten Filter angewendet werden. Anschließend$scope
können Sie andere Filter anwenden.Wie man es NICHT benutzt:
Wenden Sie nicht zuerst andere Filter an und wenden Sie dann den
ngRepeatFinish
Filter an.Wann soll ich das benutzen?
Wenn Sie nach Abschluss des Renderns der Liste bestimmte CSS-Stile auf das DOM anwenden möchten, müssen Sie die neuen Dimensionen der DOM-Elemente berücksichtigen, die vom erneut gerendert wurden
ng-repeat
. (Übrigens: Diese Art von Operationen sollten innerhalb einer Richtlinie durchgeführt werden.)Was Sie in der Funktion, die das
ngRepeatFinished
Ereignis behandelt, NICHT tun sollten :Führen Sie
$scope.$apply
in dieser Funktion keine aus, da sonst Angular in eine Endlosschleife versetzt wird, die Angular nicht erkennen kann.Verwenden Sie es nicht, um Änderungen an den
$scope
Eigenschaften vorzunehmen , da diese Änderungen erst in der nächsten$digest
Schleife in Ihrer Ansicht wiedergegeben werden und da Sie keine Änderungen vornehmen können, sind$scope.$apply
sie nicht von Nutzen."Aber Filter sollen nicht so verwendet werden !!"
Nein, das sind sie nicht. Dies ist ein Hack. Wenn Sie ihn nicht mögen, verwenden Sie ihn nicht. Wenn Sie einen besseren Weg kennen, um dasselbe zu erreichen, lassen Sie es mich bitte wissen.
Zusammenfassen
quelle
$last
Element geändert wird, funktioniert eine einfachengRepeatFinish
Anweisung, die$last
jetzt überprüft wird. Sobald ngRepeatFinish aufgerufen wird, entferne ich Dummy-Elemente. (Ich verstecke es auch mit CSS, damit es nicht kurz erscheint)Mark Rajcok
funktioniert perfekt bei jedem erneuten Rendern der ng-Wiederholung (z. B. aufgrund eines Modellwechsels). Diese hackige Lösung ist also nicht erforderlich.Wenn Sie verschiedene Funktionen für verschiedene ng-Wiederholungen auf demselben Controller aufrufen müssen, können Sie Folgendes versuchen:
Die Richtlinie:
Fangen Sie in Ihrem Controller Ereignisse mit $ on ab:
In Ihrer Vorlage mit mehreren ng-repeat
quelle
Die anderen Lösungen funktionieren beim ersten Laden der Seite einwandfrei. Der Aufruf von $ timeout vom Controller aus ist jedoch die einzige Möglichkeit, um sicherzustellen, dass Ihre Funktion aufgerufen wird, wenn sich das Modell ändert. Hier ist eine funktionierende Geige , die $ timeout verwendet. Für Ihr Beispiel wäre es:
ngRepeat wertet eine Direktive nur aus, wenn der Zeileninhalt neu ist. Wenn Sie also Elemente aus Ihrer Liste entfernen, wird onFinishRender nicht ausgelöst. Versuchen Sie beispielsweise, Filterwerte in diese ausgegebenen Geigen einzugeben .
quelle
ta
in$scope.$watch("ta",...
?Wenn Sie nicht abgeneigt sind, Requisiten im Doppel-Dollar-Bereich zu verwenden, und eine Direktive schreiben, deren einziger Inhalt eine Wiederholung ist, gibt es eine ziemlich einfache Lösung (vorausgesetzt, Sie kümmern sich nur um das anfängliche Rendern). In der Link-Funktion:
Dies ist nützlich für Fälle, in denen Sie eine Direktive haben, die DOM-Manipulationen basierend auf den Breiten oder Höhen der Mitglieder einer gerenderten Liste durchführen muss (was meiner Meinung nach der wahrscheinlichste Grund ist, warum man diese Frage stellen würde), aber nicht so allgemein als die anderen vorgeschlagenen Lösungen.
quelle
Eine Lösung für dieses Problem mit einem gefilterten ngRepeat könnten Mutationsereignisse gewesen sein , die jedoch veraltet sind (ohne sofortigen Ersatz).
Dann dachte ich an eine andere einfache:
Dadurch werden die Node.prototype-Methoden des übergeordneten Elements mit einem Timeout von einem Tick $ verknüpft, um nach aufeinanderfolgenden Änderungen zu suchen.
Es funktioniert meistens richtig, aber ich habe einige Fälle bekommen, in denen das altDone zweimal aufgerufen wurde.
Nochmals ... fügen Sie diese Anweisung dem übergeordneten Element von ngRepeat hinzu.
quelle
appendChild
(da ich nurinsertBefore
und verwendet haberemoveChild
) im obigen Code.Sehr einfach, so habe ich es gemacht.
quelle
Bitte werfen Sie einen Blick auf die Geige http://jsfiddle.net/yNXS2/ . Da die von Ihnen erstellte Direktive keinen neuen Bereich erstellt hat, habe ich den Weg fortgesetzt.
$scope.test = function(){...
hat das möglich gemacht.quelle
Ich bin sehr überrascht, nicht die einfachste Lösung unter den Antworten auf diese Frage zu sehen. Sie möchten
ngInit
Ihrem wiederholten Element (dem Element mit derngRepeat
Direktive) eine Direktive hinzufügen, nach der gesucht wird$last
(eine spezielle Variable, deren GültigkeitsbereichngRepeat
angibt, dass das wiederholte Element das letzte in der Liste ist). Wenn dies$last
zutrifft, rendern wir das letzte Element und können die gewünschte Funktion aufrufen.Der vollständige Code für Ihr HTML-Markup lautet:
Sie benötigen keinen zusätzlichen JS-Code in Ihrer App außer der Bereichsfunktion, die Sie aufrufen möchten (in diesem Fall
test
), dangInit
diese von Angular.js bereitgestellt wird. Stellen Sie einfach sicher, dass Ihretest
Funktion im Bereich enthalten ist, damit Sie über die Vorlage darauf zugreifen können:quelle