Angenommen, ich habe eine ng-Wiederholung mit einem großen Array.
Wenn ng-repeat ausgeführt wird, wird jedes Element dieses Arrays einem isolierten Bereich hinzugefügt und das Array selbst in einem Bereich gespeichert. Das bedeutet, dass $ Digest das gesamte Array auf Änderungen überprüft und darüber hinaus jedes einzelne Element in diesem Array auf Änderungen überprüft .
Sehen Sie diesen Plunker als Beispiel dafür, wovon ich spreche.
In meinem Anwendungsfall ändere ich nie ein einzelnes Element meines Arrays, sodass ich sie nicht beobachten muss. Ich werde immer nur das gesamte Array ändern. In diesem Fall würde ng-repeat die Tabelle in ihrer Gesamtheit neu rendern. (Wenn ich mich irre, lass es mich wissen.)
In einem Array von (sagen wir) 1000 Zeilen sind das 1000 weitere Ausdrücke, die ich nicht auswerten muss.
Wie kann ich jedes Element vom Watcher abmelden, während ich noch das Hauptarray beobachte?
Vielleicht könnte ich, anstatt mich abzumelden, mehr Kontrolle über meinen $ Digest haben und irgendwie jede einzelne Zeile überspringen?
Dieser spezielle Fall ist tatsächlich ein Beispiel für ein allgemeineres Problem. Ich weiß, dass $ watch eine Abmeldungsfunktion zurückgibt , aber das hilft nicht, wenn eine Direktive die Uhren registriert, was die meiste Zeit der Fall ist.
$ watch gibt eine Funktion zurück, die die $ watch beim Aufruf aufhebt. Das ist also alles, was Sie für "watchOnce" brauchen:
var unwatchValue = scope.$watch('value', function(newValue, oldValue) { // Do your thing unwatchValue(); });
quelle
Bearbeiten: Siehe die andere Antwort, die ich gepostet habe.
Ich habe Bleshs Idee auf eine trennbare Weise umgesetzt. Meine
ngOnce
Direktive zerstört nur den untergeordneten Bereich,ngRepeat
der für jedes Element erstellt wird. Dies bedeutet, dass der Bereich nicht von den Eltern erreicht wirdscope.$digest
und die Beobachter niemals ausgeführt werden.Quelle und Beispiel für JSFiddle
Die Richtlinie selbst:
angular.module('transclude', []) .directive('ngOnce', ['$timeout', function($timeout){ return { restrict: 'EA', priority: 500, transclude: true, template: '<div ng-transclude></div>', compile: function (tElement, tAttrs, transclude) { return function postLink(scope, iElement, iAttrs, controller) { $timeout(scope.$destroy.bind(scope), 0); } } }; }]);
Es benutzen:
<li ng-repeat="item in contents" ng-once> {{item.title}}: {{item.text}} </li>
Note erstellt
ng-once
keinen eigenen Bereich, was bedeutet, dass sich dies auf Geschwisterelemente auswirken kann. Diese machen alle dasselbe:<li ng-repeat="item in contents" ng-once> {{item.title}}: {{item.text}} </li> <li ng-repeat="item in contents"> <ng-once> {{item.title}}: {{item.text}} </ng-once> </li> <li ng-repeat="item in contents"> {{item.title}}: {{item.text}} <ng-once></ng-once> </li>
Beachten Sie, dass dies eine schlechte Idee sein kann
quelle
Sie können die
bindonce
Direktive zu Ihrer hinzufügenng-repeat
. Sie müssen es von https://github.com/pasvaz/bindonce herunterladen .bearbeiten : ein paar Vorbehalte:
Wenn Sie
{{}}
in Ihrer Vorlage Interpolation verwenden, müssen Sie diese durch ersetzen<span bo-text>
.Wenn Sie
ng-
Direktiven verwenden, müssen Sie diese durch die richtigenbo-
Direktiven ersetzen .Auch, wenn Sie setzen sind
bindonce
undng-repeat
auf demselben Elemente, sollten Sie versuchen , entweder das Bewegungsbindonce
zu einem übergeordneten Elemente (siehe https://github.com/Pasvaz/bindonce/issues/25#issuecomment-25457970 ) oder das Hinzufügentrack by
zu Ihremng-repeat
.quelle
Wenn Sie
angularjs 1.3
oder höher verwenden, können Sie die Einzelbindungssyntax als verwenden<li ng-repeat="item in ::contents">{{item}}</li>
Dies bindet den Wert und entfernt die Beobachter, sobald der erste Digest-Zyklus ausgeführt wird und sich der Wert
undefined
zumdefined
ersten Mal von bis ändert .Ein sehr hilfreicher BLOG dazu.
quelle