AngularJS : Difference Between The Observe And Observeandwatch Methods


Answer :

$observe() is a method on the Attributes object, and as such, it can only be used to observe/watch the value change of a DOM attribute. It is only used/called inside directives. Use $observe when you need to observe/watch a DOM attribute that contains interpolation (i.e., {{}}'s).
E.g., attr1="Name: {{name}}", then in a directive: attrs.$observe('attr1', ...).
(If you try scope.$watch(attrs.attr1, ...) it won't work because of the {{}}s -- you'll get undefined.) Use $watch for everything else.

$watch() is more complicated. It can observe/watch an "expression", where the expression can be either a function or a string. If the expression is a string, it is parsed(i.e.,evaluatedasanAngularexpression)intoafunction.(Itisthisfunctionthatiscalledeverydigestcycle.)Thestringexpressioncannotcontains.parse'd (i.e., evaluated as an Angular expression) into a function. (It is this function that is called every digest cycle.) The string expression can not contain {{}}'s. watch is a method on the Scope object, so it can be used/called wherever you have access to a scope object, hence in

  • a controller -- any controller -- one created via ng-view, ng-controller, or a directive controller
  • a linking function in a directive, since this has access to a scope as well

Because strings are evaluated as Angular expressions, $watch is often used when you want to observe/watch a model/scope property. E.g., attr1="myModel.some_prop", then in a controller or link function: scope.$watch('myModel.some_prop', ...) or scope.$watch(attrs.attr1, ...) (or scope.$watch(attrs['attr1'], ...)).
(If you try attrs.$observe('attr1') you'll get the string myModel.some_prop, which is probably not what you want.)

As discussed in comments on @PrimosK's answer, all observesandobserves and watches are checked every digest cycle.

Directives with isolate scopes are more complicated. If the '@' syntax is used, you can $observe or $watch a DOM attribute that contains interpolation (i.e., {{}}'s). (The reason it works with watchisbecausethe@syntaxdoestheinterpolationforus,hencewatch is because the '@' syntax does the interpolation for us, hence watch sees a string without {{}}'s.) To make it easier to remember which to use when, I suggest using $observe for this case also.

To help test all of this, I wrote a Plunker that defines two directives. One (d1) does not create a new scope, the other (d2) creates an isolate scope. Each directive has the same six attributes. Each attribute is both observedandobserve'd and watch'ed.

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

Look at the console log to see the differences between observeandobserve and watch in the linking function. Then click the link and see which observesandobserves and watches are triggered by the property changes made by the click handler.

Notice that when the link function runs, any attributes that contain {{}}'s are not evaluated yet (so if you try to examine the attributes, you'll get undefined). The only way to see the interpolated values is to use observe(orobserve (or watch if using an isolate scope with '@'). Therefore, getting the values of these attributes is an asynchronous operation. (And this is why we need the observeandobserve and watch functions.)

Sometimes you don't need observeorobserve or watch. E.g., if your attribute contains a number or a boolean (not a string), just evaluate it once: attr1="22", then in, say, your linking function: var count = scope.$eval(attrs.attr1). If it is just a constant string – attr1="my string" – then just use attrs.attr1 in your directive (no need for $eval()).

See also Vojta's google group post about $watch expressions.


If I understand your question right you are asking what is difference if you register listener callback with $watch or if you do it with $observe.

Callback registerd with $watch is fired when $digest is executed.

Callback registered with $observe are called when value changes of attributes that contain interpolation (e.g. attr="{{notJetInterpolated}}").


Inside directive you can use both of them on very similar way:

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

or

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

Comments

Popular posts from this blog

Are Regular VACUUM ANALYZE Still Recommended Under 9.1?

Can Feynman Diagrams Be Used To Represent Any Perturbation Theory?