AngularJS: Unterschied zwischen den Methoden $ watch und $ watch

378

Ich weiß, dass beide Watchersund Observersberechnet werden, sobald sich etwas $scopein AngularJS ändert. Aber ich konnte nicht verstehen, was genau der Unterschied zwischen den beiden ist.

Mein anfängliches Verständnis ist, dass Observersfür Winkelausdrücke berechnet werden, die Bedingungen auf der HTML-Seite sind, die Watchersausgeführt werden, wenn die $scope.$watch()Funktion ausgeführt wird. Denke ich richtig

Abilash
quelle
1
Ihre Bearbeitung ist nicht hilfreich und etwas antagonisierend. Bitte nehmen Sie Rücksicht auf andere, die hierher kommen, um Hilfe zu erhalten.
Smalone
@smalone geändert. Danke und Entschuldigung!
Abilash
👍 Keine Sorge. Vielen Dank für die Korrektur.
Smalone

Antworten:

608

$ watch () ist eine Methode für das Attributes- Objekt und kann daher nur zum Beobachten / Beobachten der Wertänderung eines DOM-Attributs verwendet werden. Es wird nur in Direktiven verwendet / aufgerufen. Verwenden Sie $ beobachten, wenn Sie ein DOM-Attribut beobachten / beobachten müssen, das Interpolation enthält (dh {{}}).
ZBattr1="Name: {{name}}"dann in einer Richtlinie :attrs.$observe('attr1', ...).
(Wenn Sie es versuchenscope.$watch(attrs.attr1, ...), funktioniert es aufgrund der {{}} s nicht - Sie erhaltenundefined.) Verwenden Sie $ watch für alles andere.

$ watch () ist komplizierter. Es kann einen "Ausdruck" beobachten / beobachten, wobei der Ausdruck entweder eine Funktion oder eine Zeichenfolge sein kann. Wenn der Ausdruck eine Zeichenfolge ist, wird $ parse 'd (dh als Winkelausdruck ausgewertet) in eine Funktion umgewandelt. (Diese Funktion wird bei jedem Digest-Zyklus aufgerufen.) Der Zeichenfolgenausdruck darf keine {{}} enthalten. $ watch ist eine Methode für das Scope- Objekt, sodass sie überall dort verwendet / aufgerufen werden kann, wo Sie Zugriff auf ein Scope-Objekt haben

  • Ein Controller - ein beliebiger Controller - einer, der über ng-view, ng-controller oder einen Direktiven-Controller erstellt wurde
  • eine Verknüpfungsfunktion in einer Direktive, da diese auch Zugriff auf einen Bereich hat

Da Zeichenfolgen als Winkelausdrücke ausgewertet werden, wird $ watch häufig verwendet, wenn Sie eine Modell- / Bereichseigenschaft beobachten / beobachten möchten. ZB attr1="myModel.some_prop"dann in einer Controller- oder Link-Funktion: scope.$watch('myModel.some_prop', ...)oder scope.$watch(attrs.attr1, ...)(oder scope.$watch(attrs['attr1'], ...)).
(Wenn Sie es versuchen, erhalten attrs.$observe('attr1')Sie die Zeichenfolge myModel.some_prop, die wahrscheinlich nicht Ihren Wünschen entspricht.)

Wie in den Kommentaren zur Antwort von @ PrimosK erläutert, werden alle $ Beobachtungen und $ Uhren in jedem Verdauungszyklus überprüft .

Richtlinien mit isolierten Bereichen sind komplizierter. Wenn die '@' - Syntax verwendet wird, können Sie ein DOM-Attribut, das Interpolation enthält (dh {{}}) , $ beobachten oder $ beobachten . (Der Grund, warum es mit $ watch funktioniert, ist, dass die '@' - Syntax die Interpolation für uns übernimmt. Daher sieht $ watch einen String ohne {{}}.) Um sich leichter zu merken, welcher wann verwendet werden soll, schlage ich vor, ihn zu verwenden $ auch für diesen Fall beachten.

Um all dies zu testen, habe ich einen Plunker geschrieben , der zwei Anweisungen definiert. One ( d1) erstellt keinen neuen Bereich, der andere ( d2) erstellt einen isolierten Bereich. Jede Direktive hat die gleichen sechs Attribute. Jedes Attribut wird sowohl $ beobachtet als auch $ beobachtet.

<div d1 attr1="{{prop1}}-test" attr2="prop2" attr3="33" attr4="'a_string'"
        attr5="a_string" attr6="{{1+aNumber}}"></div>

Sehen Sie sich das Konsolenprotokoll an, um die Unterschiede zwischen $ watch und $ watch in der Verknüpfungsfunktion zu sehen. Klicken Sie dann auf den Link und sehen Sie, welche $ Beobachtungen und $ Uhren durch die vom Klick-Handler vorgenommenen Eigenschaftsänderungen ausgelöst werden.

Beachten Sie, dass beim Ausführen der Verknüpfungsfunktion alle Attribute, die {{}} enthalten, noch nicht ausgewertet werden (wenn Sie also versuchen, die Attribute zu untersuchen, erhalten Sie undefined). Die einzige Möglichkeit, die interpolierten Werte anzuzeigen, ist die Verwendung von $ watch (oder $ watch, wenn ein isolierter Bereich mit '@' verwendet wird). Daher ist das Abrufen der Werte dieser Attribute eine asynchrone Operation. (Und deshalb brauchen wir die Funktionen $ watch und $ watch.)

Manchmal braucht man nicht $ beobachten oder $ beobachten. Wenn Ihr Attribut beispielsweise eine Zahl oder einen Booleschen Wert (keine Zeichenfolge) enthält, werten Sie ihn nur einmal aus: attr1="22"Dann beispielsweise in Ihrer Verknüpfungsfunktion : var count = scope.$eval(attrs.attr1). Wenn es sich nur um eine konstante Zeichenfolge handelt - attr1="my string"- verwenden Sie sie einfach attrs.attr1in Ihrer Direktive ($ eval () ist nicht erforderlich).

Siehe auch Vojtas Google-Gruppenbeitrag über $ watch-Ausdrücke.

Mark Rajcok
quelle
13
Tolle Erklärung! +1
PrimosK
4
Gute Antwort! Haben Sie Ahnung , warum ng-src/ng-hrefGebrauch attr.$observestatt scope.$watchdann?
Ok,
4
+1 Für den AngularJS Papst! Jedes Mal, wenn ich in Stack nach Informationen zu meinem neuesten Angular-Problem suche, lese ich unweigerlich die von @MarkRajcok akzeptierte Antwort.
GFoley83
1
Danke für einen tollen Beitrag. scope. $ eval (item) ist wirklich hilfreich. Wenn item eine JSON-Zeichenfolge ist, wird es in ein JSON-Objekt konvertiert.
Bnguyen82
5
@tamakisquare, sie sind bei Verwendung der @Syntax austauschbar . Ich glaube, es gibt keinen Leistungsunterschied (aber ich habe mir den tatsächlichen Quellcode nicht angesehen).
Mark Rajcok
25

Wenn ich Ihre Frage richtig verstehe, fragen Sie, was der Unterschied ist, wenn Sie einen Listener-Rückruf bei registrieren $watchoder wenn Sie dies tun $observe.

Callback registerd with $watchwird ausgelöst, wenn $digestes ausgeführt wird.

Rückruf registriert mit $observewird aufgerufen, wenn sich der Wert von Attributen ändert, die Interpolation enthalten (z attr="{{notJetInterpolated}}". B. ).


Innerhalb der Direktive können Sie beide auf sehr ähnliche Weise verwenden:

    attrs.$observe('attrYouWatch', function() {
         // body
    });

oder

    scope.$watch(attrs['attrYouWatch'], function() {
         // body
    });
PrimosK
quelle
3
Da sich jede Änderung in der $digestPhase widerspiegelt , kann davon ausgegangen werden, dass der $observeRückruf aufgerufen wird $digest. Ein $watchRückruf wird ebenfalls aufgerufen, $digestjedoch immer dann, wenn der Wert geändert wird. Ich denke, sie machen genau den gleichen Job: "Beobachten Sie den Ausdruck, rufen Sie die Wertänderungen zurück". Der Schlüsselwortunterschied ist möglicherweise nur syntaktischer Zucker, um den Entwickler nicht zu verwirren.
Umur Kontacı
1
@fastreload, ich stimme deinem Kommentar voll und ganz zu. Schön geschrieben!
PrimosK
@fastreload ... Danke für die wundervolle Erklärung. Wenn ich richtig verstanden habe, sind Beobachter für Winkelausdrücke. Habe ich recht?
Abilash
@PrimosK: Füge dich für meinen vorherigen Kommentar hinzu.
Abilash
2
@ Abilash-Beobachter dienen zum Beobachten von Dom-Attributen, nicht nur von Ausdrücken. Wenn Sie also den Attributwert selbst ändern, wird dies im nächsten Digest-Zyklus angezeigt.
Umur Kontacı
1

Ich denke das ist ziemlich offensichtlich:

  • $ watch wird zur Verknüpfung von Direktiven verwendet.
  • $ watch wird im Bereich verwendet, um Änderungen seiner Werte zu beobachten.

Denken Sie daran : Beide Funktionen haben zwei Argumente:

$observe/$watch(value : string, callback : function);
  • value : ist immer eine Zeichenfolgenreferenz auf das überwachte Element (der Name der Variablen eines Bereichs oder der Name des zu überwachenden Attributs der Direktive)
  • Rückruf : Die auszuführende Funktion des Formularsfunction (oldValue, newValue)

Ich habe eine gemacht plunker, damit Sie tatsächlich einen Überblick über ihre Verwendung bekommen können. Ich habe die Chamäleon-Analogie verwendet, um das Bild einfacher zu machen.

vdegenne
quelle
2
Es ist ziemlich offensichtlich über seine Verwendung. Aber warum war die Frage. Mark hat es schön zusammengefasst.
Abilash
3
Ich denke, die Parameter könnten umgeschaltet werden - es scheint, als würde newValue und dann oldValue an attrs übergeben. $ Observ (). . .
Blaster
0

Warum unterscheidet sich $ beobachten von $ beobachten?

Die watchExpression wird ausgewertet und in jedem Digest () -Zyklus mit dem vorherigen Wert verglichen. Wenn sich der watchExpression-Wert ändert, wird die watch-Funktion aufgerufen.

$ watch ist spezifisch für das Suchen nach interpolierten Werten. Wenn der Attributwert einer Direktive interpoliert wird, z. B. dir-attr="{{ scopeVar }}"wird die Beobachtungsfunktion nur aufgerufen, wenn der interpolierte Wert festgelegt ist (und daher $ Digest bereits festgelegt hat, dass Aktualisierungen erforderlich sind). Grundsätzlich gibt es bereits einen Beobachter für die Interpolation, und die $ watch-Funktion huckepack davon.

Siehe $ watch & $ set in compile.js

Niko
quelle