2013-02-14 12 views
359

So che entrambi Watchers e Observers vengono calcolati non appena qualcosa in $scope cambia in AngularJS. Ma non riuscivo a capire qual è esattamente la differenza tra i due.

La mia comprensione iniziale è che Observers sono calcolati per espressioni angolari che sono condizioni sul lato HTML dove come Watchers eseguito quando viene eseguita la funzione $scope.$watch(). Sto pensando correttamente?

+1

La modifica non è utile e un po 'antagonizzante. Per favore sii rispettoso degli altri che vengono qui per un aiuto concreto. – smalone

+0

@smalone cambiato. Grazie e scusa! – Abilash

+0

Nessun problema. Grazie per il fissaggio. – smalone

risposta

587

$observe() è un metodo sull'oggetto Attributes, e come tale, può essere usato solo per osservare/guardare il cambiamento di valore di un attributo DOM. È usato/chiamato solo all'interno delle direttive. Usa $ osserva quando devi osservare/guardare un attributo DOM che contiene l'interpolazione (cioè, {{}}).
E.g., attr1="Name: {{name}}", quindi in una direttiva: attrs.$observe('attr1', ...).
(Se si prova scope.$watch(attrs.attr1, ...) non funzionerà a causa di {{}} - si otterrà undefined.) Utilizzare $ watch per tutto il resto.

$watch() è più complicato. Può osservare/guardare una "espressione", in cui l'espressione può essere una funzione o una stringa. Se l'espressione è una stringa, è $parse 'd (vale a dire, valutata come Angular expression) in una funzione. (È questa funzione che viene chiamata ogni ciclo di digest). L'espressione di stringa non può contenere {{}}. $ Orologio è un metodo sull'oggetto Scope, in modo che possa essere utilizzato/chiamato ovunque si ha accesso a un oggetto ambito, quindi, in

  • un controller - qualsiasi controller - quello creato tramite ng-view, ng -Controller, o un controller direttiva
  • una funzione di collegamento in una direttiva, dal momento che questo ha accesso a un ambito così

poiché le stringhe sono valutate come espressioni angolari, $ orologio viene spesso utilizzato quando si vuole osservare/guarda una proprietà model/scope. Ad esempio, attr1="myModel.some_prop", quindi in una funzione controller o collegamento: scope.$watch('myModel.some_prop', ...) o scope.$watch(attrs.attr1, ...) (o scope.$watch(attrs['attr1'], ...)).
(Se si prova attrs.$observe('attr1') si otterrà la stringa myModel.some_prop, che probabilmente non è ciò che si desidera.)

Come discusso nei commenti sulla risposta di @ PrimosK, tutti gli $ observes e $ gli orologi vengono controllati ogni digest cycle.

Le direttive con ambito isolato sono più complicate. Se viene utilizzata la sintassi '@', è possibile osservare $ o $ watch un attributo DOM che contiene l'interpolazione (ad esempio, {{}}). (La ragione per cui funziona con $ watch è perché la sintassi '@' fa il interpolation per noi, quindi $ watch vede una stringa senza {{}}.) Per rendere più facile ricordare quale usare quando, suggerisco di usare $ osservare anche per questo caso.

Per testare tutto questo, ho scritto uno Plunker che definisce due direttive. Uno (d1) non crea un nuovo ambito, l'altro (d2) crea un ambito isolato. Ogni direttiva ha gli stessi sei attributi. Ogni attributo è sia $ observ'd che $ watch'ed.

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

Controllare il log della console per vedere le differenze tra $ observ e $ watch nella funzione di collegamento. Quindi fai clic sul link e vedi quali $ osserva e $ gli orologi sono attivati ​​dalle modifiche alle proprietà apportate dal gestore dei clic.

Si noti che quando viene eseguita la funzione di collegamento, gli attributi che contengono {{}} non vengono ancora valutati (quindi se si tenta di esaminare gli attributi, verrà ottenuto undefined). L'unico modo per vedere i valori interpolati è usare $ observ (o $ watch se si utilizza un ambito isolato con '@'). Pertanto, ottenere i valori di questi attributi è un'operazione asincrona. (E questo è il motivo per cui abbiamo bisogno di osservare e $ orologi funzioni $.)

A volte non occorre $ osservare o $ guardare. Ad esempio, se il tuo attributo contiene un numero o un valore booleano (non una stringa), basta valutare una volta: attr1="22", quindi, ad esempio, nella tua funzione di collegamento: var count = scope.$eval(attrs.attr1). Se si tratta solo di una stringa costante –, utilizzare semplicemente attrs.attr1 nella direttiva (non è necessario $ eval()).

Vedere anche Vojta's google group post su espressioni $ watch.

+12

Ottima spiegazione! +1 – PrimosK

+51

Questo è più utile dei documenti Angular ufficiali! Grazie! –

+4

Ottima risposta! Hai idea del perché 'ng-src/ng-href' usi' attr. $ Observ' invece di 'scope. $ Watch' allora? – okm

20

Se ho capito bene la tua domanda, stai chiedendo che differenza c'è se si registra callback listener con $watch o se lo si fa con $observe.

Il callback registerd con $watch viene generato quando viene eseguito $digest. Si prega di dare un'occhiata al docs per maggiori informazioni.

La richiamata registrata con $observe viene chiamata quando si modificano i valori degli attributi che contengono l'interpolazione (ad esempio attr="{{notJetInterpolated}}").


All'interno direttiva è possibile utilizzare entrambi su modo molto simile:

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

o

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

In realtà, poiché ogni cambiamento si riflette nella fase '$ digest ', è lecito ritenere che la richiamata' $ observ' sarà chiamata '$ digest'. Anche la callback '$ watch' verrà chiamata in' $ digest', ma ogni volta che il valore viene modificato. Penso che facciano esattamente lo stesso lavoro: "guarda l'espressione, chiama callback il valore cambia". La differenza di parole chiave è probabilmente solo zucchero sintattico per non confondere lo sviluppatore. –

+1

@fastreload, sono totalmente d'accordo con il tuo commento .. Ben scritto! – PrimosK

+0

@fastreload ... Grazie per la meravigliosa spiegazione. Se ho capito bene, gli osservatori sono per le espressioni angolari. Ho ragione? – Abilash

1

Penso che questo è abbastanza evidente:

  • $ osservare è utilizzata in funzione delle direttive di collegamento.
  • $ watch viene utilizzato su scope per osservare qualsiasi modifica dei suoi valori.

tenere presente: sia la funzione ha due argomenti,

$observe/$watch(value : string, callback : function); 
  • valore: è sempre un riferimento stringa all'elemento guardato (il nome della variabile di una portata o la nome dell'attributo della direttiva da guardare)
  • callback: la funzione da eseguire del modulo function (oldValue, newValue)

Ho creato uno plunker, in modo che possiate davvero cogliere il loro utilizzo. Ho usato l'analogia di Chameleon per rendere più facile l'immagine.

+2

È piuttosto ovvio riguardo ai suoi usi. Ma perché era la domanda. Mark l'ha riassunto splendidamente. – Abilash

+3

Penso che i parametri potrebbero essere cambiati - sembra passare il valore newValue, poi oldValue a attrs. $ Observ(). . . – blaster

Problemi correlati