381 votes

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

Je sais que les deux Watchers et Observers sont calculés dès que quelque chose dans $scope changements dans AngularJS. Mais je n'arrivais pas à comprendre quelle était la différence exacte entre les deux.

Je crois savoir que Observers sont calculés pour les expressions angulaires qui sont des conditions du côté HTML, alors que Watchers exécuté lorsque $scope.$watch() est exécutée. Est-ce que je pense correctement ?

1 votes

Votre montage n'est pas utile et est un peu antagoniste. S'il vous plaît, soyez prévenant pour les autres qui viennent ici pour une aide réelle.

0 votes

@smalone a changé. Merci et désolé !

0 votes

Pas d'inquiétude. Merci de l'avoir réparé.

612voto

Mark Rajcok Points 85912

$observe() est une méthode sur le Attributs et, en tant que tel, il ne peut être utilisé que pour observer/suivre le changement de valeur d'un attribut DOM. Il n'est utilisé/appelé qu'à l'intérieur de directives. Utilisez $observe lorsque vous devez observer/suivre un attribut DOM qui contient une interpolation (c'est-à-dire des {{}}).
Par exemple, attr1="Name: {{name}}" puis dans une directive : attrs.$observe('attr1', ...) .
(Si vous essayez scope.$watch(attrs.attr1, ...) ça ne marchera pas à cause des {{}} -- vous obtiendrez undefined .) Utilisez $watch pour tout le reste.

$watch() est plus compliqué. Il peut observer/suivre une "expression", où l'expression peut être soit une fonction, soit une chaîne de caractères. Si l'expression est une chaîne de caractères, elle est $parse (c'est-à-dire évaluée comme une Expression angulaire ) en une fonction. (C'est cette fonction qui est appelée à chaque cycle du digest). L'expression de la chaîne ne peut pas contenir de {{}}. $watch est une méthode de la classe Portée de sorte qu'il peut être utilisé/appelé partout où l'on a accès à un objet scope, d'où l'utilisation de la fonction

  • un contrôleur -- n'importe quel contrôleur -- un contrôleur créé via ng-view, ng-controller, ou un contrôleur directive
  • une fonction de liaison dans une directive, puisqu'elle a également accès à une portée.

Les chaînes étant évaluées comme des expressions Angular, $watch est souvent utilisé lorsque vous souhaitez observer/suivre une propriété de modèle/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 indiqué dans les commentaires sur la réponse de @PrimosK, tous les $observes et $watches sont vérifiés tous les jours. cycle digestif .

Les directives avec isolate scopes sont plus compliquées. Si la syntaxe '@' est utilisée, vous pouvez $observer ou $watch un attribut DOM qui contient une interpolation (c'est-à-dire des {{}}). (La raison pour laquelle cela fonctionne avec $watch est que la syntaxe '@' permet de faire l'interpolation. interpolation pour nous, donc $watch voit une chaîne sans {{}}). Pour qu'il soit plus facile de se rappeler lequel utiliser quand, je suggère d'utiliser $observe dans ce cas également.

Pour aider à tester tout cela, j'ai écrit une Plunker qui définit deux directives. La première ( d1 ) ne crée pas de nouvelle portée, l'autre ( d2 ) crée une portée isolée. Chaque directive possède les six mêmes attributs. Chaque attribut est à la fois $observe'd et $watch'ed.

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

Regardez le journal de la console pour voir les différences entre $observe et $watch dans la fonction de liaison. Ensuite, cliquez sur le lien et voyez quels $observes et $watches sont déclenchés par les changements de propriétés effectués par le gestionnaire de clics.

Notez que lorsque la fonction de liaison s'exécute, tous les attributs qui contiennent des {{}} ne sont pas encore évalués (si vous essayez d'examiner les attributs, vous obtiendrez donc undefined ). La seule façon de voir les valeurs interpolées est d'utiliser $observe (ou $watch si vous utilisez une portée isolée avec '@'). Par conséquent, pour obtenir les valeurs de ces attributs, il faut utiliser asynchrone fonctionnement. (Et c'est pourquoi nous avons besoin des fonctions $observe et $watch).

Parfois, vous n'avez pas besoin de $observe ou de $watch. Par exemple, si votre attribut contient un nombre ou un booléen (et non une chaîne), il suffit de l'évaluer une fois : attr1="22" puis dans, disons, votre fonction de liaison : var count = scope.$eval(attrs.attr1) . Si c'est juste une chaîne constante - attr1="my string" - alors utilisez simplement attrs.attr1 dans votre directive (pas besoin de $eval()).

Voir aussi Le post du groupe google de Vojta à propos des expressions $watch.

4 votes

Excellente réponse ! Avez-vous une idée de la raison pour laquelle ng-src/ng-href utiliser attr.$observe au lieu de scope.$watch alors ?

0 votes

@okm, puisqu'ils ne créent pas une portée isolée ( code source ), ils doivent utiliser $observe car les valeurs des attributs contiennent {{}} s.

4 votes

+1 pour le pape d'AngularJS ! Chaque fois que je cherche sur Stack des informations sur mon dernier problème Angular, je finis inévitablement par lire la réponse acceptée par @MarkRajcok.

25voto

PrimosK Points 5242

Si je comprends bien votre question, vous demandez quelle est la différence si vous enregistrez le callback du listener avec $watch ou si vous le faites avec $observe .

Callback enregistré avec $watch est déclenché lorsque $digest est exécuté.

Callback enregistré avec $observe sont appelés lorsque les changements de valeur des attributs qui contiennent une interpolation (par ex. attr="{{notJetInterpolated}}" ).


A l'intérieur de la directive, vous pouvez utiliser les deux de manière très similaire :

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

ou

    scope.$watch(attrs['attrYouWatch'], function() {
         // body
    });

3 votes

En fait, puisque chaque changement est reflété dans $digest il est possible de supposer que la $observe sera appelé dans $digest . Et $watch sera également appelé dans $digest mais à chaque fois que la valeur est modifiée. Je pense qu'ils font exactement le même travail : "surveiller l'expression, appeler le callback si la valeur change". La différence de mot-clé n'est peut-être qu'un sucre syntaxique pour ne pas embrouiller le développeur.

1 votes

@fastreload, je suis tout à fait d'accord avec votre commentaire Bien écrit !

0 votes

@fastreload... Merci pour cette merveilleuse explication. Si j'ai bien compris, les Observateurs sont pour les Expressions Angulaires. N'ai-je pas raison ?

1voto

Oddant Points 1063

Je pense que c'est assez évident :

  • $observe est utilisé dans la fonction de liaison des directives.
  • $watch est utilisé sur le scope pour surveiller tout changement dans ses valeurs.

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

$observe/$watch(value : string, callback : function);
  • valeur est toujours une chaîne de référence à l'élément surveillé (le nom d'une variable de la portée ou le nom de l'attribut de la directive à surveiller).
  • rappel : la fonction à exécuter de la forme function (oldValue, newValue)

J'ai fait un plunker afin que vous puissiez vous familiariser avec leur utilisation. J'ai utilisé l'analogie du caméléon pour rendre l'image plus facile à comprendre.

0voto

Niko Points 94

Pourquoi $observe est-il différent de $watch ?

L'expression watchExpression est évaluée et comparée à la valeur précédente à chaque cycle digest(), s'il y a un changement dans la valeur watchExpression, la fonction watch est appelée.

$observe est spécifique à la surveillance des valeurs interpolées. Si la valeur de l'attribut d'une directive est interpolée, par ex. dir-attr="{{ scopeVar }}" la fonction observe ne sera appelée que lorsque la valeur interpolée est définie (et donc lorsque $digest a déjà déterminé que des mises à jour doivent être effectuées). En fait, il y a déjà un observateur pour l'interpolation, et la fonction $observe s'en inspire.

Voir $observe & $set dans compiler.js

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X