Eu sei que tanto Watchers
quanto Observers
são calculados assim que algo no $scope
muda no AngularJS. Mas não conseguia entender o que exatamente é a diferença entre os dois.
Meu entendimento inicial é que Observers
são computados para expressões angulares que são condições no lado HTML onde os Watchers
executados quando a function $scope.$watch()
é executada. Eu estou pensando corretamente?
$ observe () é um método no object Attributes e, como tal, só pode ser usado para observar / observar a mudança de valor de um atributo DOM. Só é usado / chamado dentro de diretivas. Use $ observe quando você precisar observar / observar um atributo DOM que contenha interpolação (ou seja, {{}}).
Por exemplo, attr1="Name: {{name}}"
, então em uma diretiva: attrs.$observe('attr1', ...)
.
(Se você tentar o scope.$watch(attrs.attr1, ...)
não funcionará por causa dos {{}} s – você ficará undefined
.) Use $ watch para todo o resto.
$ watch () é mais complicado. Pode observar / observar uma “expressão”, onde a expressão pode ser uma function ou uma string. Se a expressão for uma string, ela será $ parse ‘d (isto é, avaliada como uma expressão Angular ) em uma function. (É essa function que é chamada todo ciclo de digitação.) A expressão de seqüência de caracteres não pode conter {{}} ‘s. $ watch é um método no object Scope , então ele pode ser usado / chamado onde quer que você tenha access a um object de escopo, portanto em
Como strings são avaliadas como expressões Angulares, $ watch é freqüentemente usado quando você deseja observar / observar uma propriedade de modelo / escopo. Por exemplo, attr1="myModel.some_prop"
, então, em um controlador ou function de link: scope.$watch('myModel.some_prop', ...)
ou scope.$watch(attrs.attr1, ...)
(ou scope.$watch(attrs['attr1'], ...)
).
(Se você tentar attrs.$observe('attr1')
você obterá a string myModel.some_prop
, que provavelmente não é o que você deseja.)
Como discutido nos comentários sobre a resposta da @PrimosK, todos os $ observes e $ watches são verificados em cada ciclo de digitação.
Diretivas com escopos isolados são mais complicadas. Se a syntax ‘@’ for usada, você poderá $ observar ou $ observar um atributo DOM que contenha interpolação (ou seja, {{}}). (O motivo pelo qual ele trabalha com $ watch é porque a syntax ‘@’ faz a interpolação para nós, portanto $ watch vê uma string sem {{}}.) Para facilitar o lembrete sobre qual usar, sugiro usar $ observe para este caso também.
Para ajudar a testar tudo isso, escrevi um Plunker que define duas diretivas. Um ( d1
) não cria um novo escopo, o outro ( d2
) cria um escopo isolado. Cada diretiva tem os mesmos seis atributos. Cada atributo é $ observado e $ monitorado.
Observe o log do console para ver as diferenças entre $ observe e $ watch na function de vinculação. Em seguida, clique no link e veja quais $ observa e $ relógios são acionados pelas alterações de propriedade feitas pelo manipulador de cliques.
Observe que quando a function de link é executada, quaisquer atributos que contenham {{}} não são avaliados ainda (portanto, se você tentar examinar os atributos, ficará undefined
). A única maneira de ver os valores interpolados é usar $ observe (ou $ watch se estiver usando um escopo isolado com ‘@’). Portanto, obter os valores desses atributos é uma operação assíncrona . (E é por isso que precisamos das funções $ observe e $ watch).
Às vezes você não precisa de $ observe ou $ watch. Por exemplo, se o seu atributo contém um número ou um booleano (não uma string), apenas avalie-o uma vez: attr1="22"
, depois, digamos, em sua function de vinculação: var count = scope.$eval(attrs.attr1)
. Se for apenas uma string constante – attr1="my string"
– então apenas use attrs.attr1
em sua diretiva (sem necessidade de $ eval ()).
Veja também o post do grupo do gojta sobre expressões de $ watch.
Se eu entendi bem a sua pergunta, você está perguntando qual é a diferença se você registrar o retorno do ouvinte com $watch
ou se você fizer isso com $observe
.
O callback registado com $watch
é acionado quando o $digest
é executado.
Callback registrado com $observe
são chamados quando alterações de valor de atributos que contêm interpolação (por exemplo, attr="{{notJetInterpolated}}"
).
Dentro da diretiva você pode usar os dois de maneira muito similar:
attrs.$observe('attrYouWatch', function() { // body });
ou
scope.$watch(attrs['attrYouWatch'], function() { // body });
Eu acho que isso é bem óbvio:
Tenha em mente : tanto a function tem dois argumentos,
$observe/$watch(value : string, callback : function);
function (oldValue, newValue)
formulário function (oldValue, newValue)
Eu fiz um plunker , então você pode realmente entender a utilização deles. Eu usei a analogia do Chameleon para tornar mais fácil a imagem.
Por que $ é diferente de $ watch?
O watchExpression é avaliado e comparado com o valor anterior em cada ciclo digest (), se houver uma alteração no valor watchExpression, a function watch é chamada.
$ observe é específico para observar valores interpolados. Se o valor de atributo de uma diretiva é interpolado, por exemplo, dir-attr="{{ scopeVar }}"
, a function observe só será chamada quando o valor interpolado for definido (e, portanto, quando $ digest já tiver determinado que as atualizações precisam ser feitas). Basicamente, já existe um observador para a interpolação, e a function $ observe pega essa function.
Veja $ observe & $ definido em compile.js