I'm reading Build Your Own AngularJS and have a decent understanding of how $scopes
, $watch
and $digest
work. I understand how it works when you add your own $watches
and and call your own $digests
. However, I'm confused about what exactly is happening by default.
What gets added to
$scope.$$watchers
by default? Everything you put on$scope
? Everything you assign anng-model
to? Both? Something else?And when exactly do
$digests
get triggered by default? Input field changes? Input fields withng-models
? Other?
Some of the common directives that use
$watch
/$watchCollection
/$watchGroup
internally:Note that the only one that sets up a two-way binding is
ng-model
(scope -> view & view -> scope).The others set up a one-way binding (scope -> view).
Simply exposing something on for example a controller´s
$scope
will not add a watcher.For example, the following will not result in a watcher being added:
Together with:
But if you replace the HTML with the following one watcher will be added:
Some common scenarios when the digest cycle is triggered:
ng-click
is evaluatedng-model
changes (for example when typing in an input)$http
service$timeout
and$interval
Note that there is one big difference between
$apply
and$digest
:Calling
scope.$digest()
will execute the watchers only on that scope and its children.Calling
scope.$apply()
will trigger$digest
on the$rootScope
, which means all the scopes will be traversed and all watchers executed.$apply
also accepts an expression as an argument. This expression will be evaluated inside a try-catch statement and any exception will be passed on to the$exceptionHandler
service.$digest
does not accept any arguments.Usually you only call
$digest
instead of$apply
when you are chasing micro optimizations and really know what you are doing.It's my understanding that any two-way bindings get a
$watch
in their scope, however, if it is added by angular internals, you don't get that hook, because, for example,ngModelController
has the callback, so you can't use that callback, I think what is on scope does not get a watch unless it is bound to the view.$digest
is not used on model binding from what I found in the source code - but I found plenty of uses of$apply
. In fact I found very few uses of$digest
in the angular code at all. I didn't look in every file, but I did find it used in the expression parser here. Which I find interesting, but to answer your question,$digest
in not called often, and$apply
is called on only a few occasions with model binding, most notably on$commitViewValue()
in thengModelController
. It also calls apply when an input is "touched"(ng-touched
). I also found that$evalAsync
calls$digest
as well.What I found for certain on apply/digest:
As you can see, apply is really just a safe wrap around
$digest
, so one might argue to use $apply over digest. According to the source $digest does some crazy while-loop$scope
traversal.TLDR;
The notes from the angular team on digest: