AngularJS: diferencia entre los métodos $observe y $watch

Resuelto Abilash asked hace 11 años • 4 respuestas

Sé que ambos Watchersy Observersse calculan tan pronto como algo $scopecambia en AngularJS. Pero no pude entender cuál es exactamente la diferencia entre los dos.

Mi comprensión inicial es que Observersse calculan para expresiones angulares que son condiciones en el lado HTML donde se Watchersejecutan cuando $scope.$watch()se ejecuta la función. ¿Estoy pensando correctamente?

Abilash avatar Feb 14 '13 20:02 Abilash
Aceptado

$observe() es un método en el objeto Attributes y, como tal, solo se puede usar para observar/observar el cambio de valor de un atributo DOM. Solo se usa/llama dentro de directivas. Utilice $observe cuando necesite observar/observar un atributo DOM que contiene interpolación (es decir, {{}}).
Ej.,attr1="Name: {{name}}", entonces en una directiva:attrs.$observe('attr1', ...).
(Si lo intentas,scope.$watch(attrs.attr1, ...)no funcionará debido a los {{}}, obtendrásundefined). Usa $watch para todo lo demás.

$watch() es más complicado. Puede observar/observar una "expresión", donde la expresión puede ser una función o una cadena. Si la expresión es una cadena, se $parse 'd (es decir, se evalúa como una expresión angular ) en una función. (Es esta función la que se llama en cada ciclo de resumen). La expresión de cadena no puede contener {{}}. $watch es un método en el objeto Scope , por lo que se puede usar/llamar siempre que tenga acceso a un objeto de alcance, por lo tanto, en

  • un controlador, cualquier controlador, uno creado mediante ng-view, ng-controller o un controlador directivo
  • una función de enlace en una directiva, ya que esta también tiene acceso a un alcance

Debido a que las cadenas se evalúan como expresiones angulares, $watch se usa a menudo cuando se desea observar/observar una propiedad de modelo/alcance. Por ejemplo, attr1="myModel.some_prop", luego en un controlador o función de enlace: scope.$watch('myModel.some_prop', ...)o scope.$watch(attrs.attr1, ...)(o scope.$watch(attrs['attr1'], ...)).
(Si lo intentas, attrs.$observe('attr1')obtendrás la cadena myModel.some_prop, que probablemente no sea lo que deseas).

Como se analizó en los comentarios sobre la respuesta de @ PrimosK, todos los $observes y $watches se verifican en cada ciclo de resumen .

Las directivas con alcances aislados son más complicadas. Si se utiliza la sintaxis '@', puede $observar o $ver un atributo DOM que contiene interpolación (es decir, {{}}). (La razón por la que funciona con $watch es porque la sintaxis '@' realiza la interpolación por nosotros, por lo tanto, $watch ve una cadena sin {{}}). Para que sea más fácil recordar cuál usar y cuándo, sugiero usar $observe también para este caso.

Para ayudar a probar todo esto, escribí un Plunker que define dos directivas. Uno ( d1) no crea un ámbito nuevo, el otro ( d2) crea un ámbito aislado. Cada directiva tiene los mismos seis atributos. Cada atributo es $observado y $vigilado.

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

Mire el registro de la consola para ver las diferencias entre $observe y $watch en la función de vinculación. Luego haga clic en el enlace y vea qué $observes y $watches se activan mediante los cambios de propiedad realizados por el controlador de clics.

Tenga en cuenta que cuando se ejecuta la función de enlace, los atributos que contienen {{}} aún no se evalúan (por lo que si intenta examinar los atributos, obtendrá undefined). La única forma de ver los valores interpolados es usar $observe (o $watch si usa un alcance aislado con '@'). Por tanto, obtener los valores de estos atributos es una operación asincrónica . (Y es por eso que necesitamos las funciones $observe y $watch).

A veces no necesitas $observe o $watch. Por ejemplo, si su atributo contiene un número o un valor booleano (no una cadena), simplemente evalúelo una vez: attr1="22"y luego, digamos, en su función de enlace var count = scope.$eval(attrs.attr1):. Si es solo una cadena constante – attr1="my string"– entonces simplemente úsela attrs.attr1en su directiva (no es necesario $eval()).

Consulte también la publicación del grupo de Google de Vojta sobre expresiones $watch.

Mark Rajcok avatar Feb 16 '2013 06:02 Mark Rajcok

Si entiendo bien su pregunta, se pregunta cuál es la diferencia si registra la devolución de llamada del oyente con $watcho si lo hace con $observe.

La devolución de llamada registrada $watchse activa cuando $digestse ejecuta.

Las devoluciones de llamada registradas con $observese llaman cuando el valor cambia de los atributos que contienen interpolación (por ejemplo attr="{{notJetInterpolated}}").


Dentro de la directiva puedes usar ambas de manera muy similar:

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

o

    scope.$watch(attrs['attrYouWatch'], function() {
         // body
    });
PrimosK avatar Feb 14 '2013 14:02 PrimosK