Je sais que Watchers
et Observers
sont calculés dès que quelque chose dans $scope
change dans AngularJS. Mais je ne pouvais pas comprendre quelle est exactement la différence entre les deux.
Ma compréhension initiale est que Observers
sont calculés pour les expressions angulaires qui sont des conditions du côté HTML où Watchers
est exécuté lorsque la fonction $scope.$watch()
est exécutée. Est-ce que je pense bien?
$ OBSERVE () est une méthode de l'objet Attributes et ne peut donc être utilisée que pour observer/observer le changement de valeur d'un attribut DOM. Il est uniquement utilisé/appelé directives internes. Utilisez $ observe lorsque vous devez observer/observer un attribut DOM qui contient une interpolation (c'est-à-dire, les {{}}).
Par exemple, attr1="Name: {{name}}"
, puis dans une directive: attrs.$observe('attr1', ...)
.
(Si vous essayez scope.$watch(attrs.attr1, ...)
, cela ne fonctionnera pas à cause du {{}} s - vous obtiendrez undefined
.) Utilisez $ watch pour tout le reste.
$ WATCH () est plus compliqué. Il peut observer/regarder une "expression", où l'expression peut être une fonction ou une chaîne. Si l'expression est une chaîne, elle est $ parse 'd (c'est-à-dire évaluée en tant que expression angulaire ) dans une fonction. (C'est cette fonction qui est appelée à chaque cycle de résumé.) L'expression de chaîne ne peut pas contenir les {{}}. $ watch est une méthode sur l’objet Scope , elle peut donc être utilisée/appelée partout où vous avez accès à un objet scope, donc dans
Comme les chaînes sont évaluées en tant qu'expressions angulaires, $ watch est souvent utilisé lorsque vous souhaitez observer/regarder une propriété model/scope. Par exemple, attr1="myModel.some_prop"
, puis dans une fonction de contrôleur ou de liaison: scope.$watch('myModel.some_prop', ...)
ou scope.$watch(attrs.attr1, ...)
(ou scope.$watch(attrs['attr1'], ...)
) .
(Si vous essayez attrs.$observe('attr1')
, vous obtiendrez la chaîne myModel.some_prop
, ce qui n'est probablement pas ce que vous voulez.)
Comme discuté dans les commentaires sur la réponse de @ PrimosK, tous les $ observes et $ montres sont vérifiés tous les cycles de digestion .
Les directives avec des portées isolées sont plus compliquées. Si la syntaxe '@' est utilisée, vous pouvez $ observer ou $ regarder un attribut DOM contenant une interpolation (c'est-à-dire des {{}}). (La raison pour laquelle cela fonctionne avec $ watch est parce que la syntaxe '@' fait le interpolation pour nous, donc $ watch voit une chaîne sans celle de {{}}.) Pour faciliter la tâche utiliser quand, je suggère également d’utiliser $ observe pour ce cas.
Pour aider à tester tout cela, j'ai écrit un Plunker qui définit deux directives. L'un (d1
) ne crée pas de nouvelle portée, l'autre (d2
) crée une portée isolée. Chaque directive a les six mêmes attributs. Chaque attribut est à la fois $ observé et $ surveillé.
<div d1 attr1="{{prop1}}-test" attr2="prop2" attr3="33" attr4="'a_string'"
attr5="a_string" attr6="{{1+aNumber}}"></div>
Consultez le journal de la console pour voir les différences entre $ observe et $ watch dans la fonction de liaison. Cliquez ensuite sur le lien et voyez quels $ observes et $ montres sont déclenchés par les modifications de propriétés apportées par le gestionnaire de clics.
Notez que lorsque la fonction de lien est exécutée, tous les attributs contenant des {{}} ne sont pas encore évalués (ainsi, si vous essayez d'examiner les attributs, vous aurez undefined
). La seule façon de voir les valeurs interpolées est d'utiliser $ observe (ou $ watch si vous utilisez une étendue d'isolement avec '@'). Par conséquent, obtenir les valeurs de ces attributs est une opération asynchrone. (Et c’est pourquoi nous avons besoin des fonctions $ observ et $ watch.)
Parfois, vous n'avez pas besoin de $ observ ou de $ watch. Par exemple, si votre attribut contient un nombre ou un booléen (pas une chaîne), évaluez-le une seule fois: attr1="22"
, puis dans, disons, votre fonction de liaison: var count = scope.$eval(attrs.attr1)
. S'il ne s'agit que d'une chaîne constante - attr1="my string"
-, il vous suffit d'utiliser attrs.attr1
dans votre directive (nul besoin de $ eval ()).
Voir aussi message de groupe de Vojta sur Google à propos de $ watch expressions.
Si j'ai bien compris votre question, vous demandez quelle est la différence si vous enregistrez un rappel d'auditeur avec $watch
ou si vous le faites avec $observe
.
Le rappel enregistré avec $watch
est déclenché lorsque $digest
est exécuté.
Les rappels enregistrés avec $observe
sont appelés lorsque des modifications de valeur d'attributs contenant une interpolation (par exemple attr="{{notJetInterpolated}}"
).
Dans la directive, vous pouvez utiliser les deux de la même manière:
attrs.$observe('attrYouWatch', function() {
// body
});
ou
scope.$watch(attrs['attrYouWatch'], function() {
// body
});
Je pense que c'est assez évident:
Gardez à l'esprit : la fonction a deux arguments,
$observe/$watch(value : string, callback : function);
function (oldValue, newValue)
J'ai fait un plunker , afin que vous puissiez réellement comprendre à la fois leur utilisation. J'ai utilisé l'analogie Caméléon pour la rendre plus facile à visualiser.
Pourquoi $ observe est-il différent de $ watch?
La valeur watchExpression est évaluée et comparée à la valeur précédente de chaque cycle digest (). Si la valeur watchExpression change, la fonction watch est appelée.
$ observe est spécifique à la surveillance de valeurs interpolées. Si la valeur d'attribut d'une directive est interpolée, par exemple dir-attr="{{ scopeVar }}"
, la fonction observe ne sera appelée que lorsque la valeur interpolée sera définie (et donc lorsque $ digest aura déjà déterminé que des mises à jour doivent être effectuées). En gros, il y a déjà un observateur pour l'interpolation, et la fonction $ observe le greffe.
Voir $ observer & $ set dans compile.js