web-dev-qa-db-fra.com

AngularJS: Différence entre les méthodes $ observe et $ watch

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?

372
Abilash

$ 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 

  • un contrôleur - n'importe quel contrôleur - créé avec ng-view, ng-controller ou un contrôleur de directive
  • une fonction de liaison dans une directive, car elle a également accès à un champ

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.

602
Mark Rajcok

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
    });
23
PrimosK

Je pense que c'est assez évident:

  • $ observe est utilisé dans la fonction de liaison des directives.
  • $ watch est utilisé sur l'oscilloscope pour suivre l'évolution de ses valeurs.

Gardez à l'esprit : la fonction a deux arguments,

$observe/$watch(value : string, callback : function);
  • value : est toujours une référence de chaîne à l'élément surveillé (le nom de la variable d'une étendue ou le nom de l'attribut de la directive à surveiller)
  • callback : fonction à exécuter de la forme 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.

1
vdegenne

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

0
Niko