$apply() and $digest() : how do they work?

Maria Cristina Di Termine
08-03-2017

In this post I would like to write a bit about two specific features of AngularJS: $apply() and $digest(). These two aspects of the framework are sometimes confusing but they are also very important to fully understand how AngularJS works.
AngularJS is a framework of JavaScript for dynamic web applications and his synchronization between the model and the view is two way data binding. It means that when something in the view gets changed, also the scope model gets updated with the new value and viceversa if the scope changes, also the view will change in the same moment. AngularJS is meanly based on this process, but how is this possible? How does exactly Angular work?
Every time we set an expression, the framework create a watcher in the scope that will updates the view if the scope change.
We can also set a watcher manually using this syntax:

   $scope.$watch('myModel', function(newValue, oldValue) {
    //some function
    });

Let’s imagine to have an expression in the view: {{myModel}}. Thank to the watcher, when “myModel” changes in scope, it calls the second argument passed in $watch (the listener function) and this function updates the expression in the view.

But how does Angular know when to fire the watcher?
The watcher is fired in the $digest loop. This is the “heartbeat” of an AngularJS application. $digest processes all the watch expressions of the current scope. When the $watch is fired basically the value of the current watch expression is compared with the value of the previous expression, and if they are not equal, then it is “dirty” and the listener is fired.
The $digest cycle starts as a result of a call to $scope.$digest(). If we for example change the scope model using an ng-click directive, Angular would trigger a $digest automatically calling $digest(). The $digest cycle then fires all the watchers which will check if the value has changed and if it’s so then will fire the listener function.

Can be useful to know that there are several other directives and services that let you change models and automatically trigger a $digest like for example $timeout and ng-model.

In these cases, Angular doesn’t call $digest() directly. When the button in the view is clicked, Angular calls $scope.apply() which then calls $rootScope.$digest(). So like this, the $digest starts at the $rootScope and after that it checks all the scopes and call all the watchers it finds.

The $scope.$apply() automatically calls $rootScope.$digest() and it can run in two different ways:
– One version takes a function as an argument, evaluates it, and triggers a $digest cycle.
– The other version does not take any arguments and just starts a $digest cycle when is called.

When do we need to call $apply() manually then?
You need to call apply() manually only if you change a model outside of the Angular context, then you need to tell Angular about the changes by calling $apply() manually. Like this we tell Angular to fire the watchers because we changed some models. An example is when we use the method of JavaScript setTimeout() to update the scope model. In this case Angular doesn’t know what we are gonna to change, that’s why we need to call $apply() manually which will trigger the $digest() cycle. More common is also for example we a directive in which we trigger a event listener to the DOM to change some models. Also in this case, we need to call $apply() inside the handler function to be sure the changes are updated.

By the way is good to know that the $timeout service runs automatically $apply() and it’s a good practice to use $timeout instead calling $apply() manually.

I hope this post can make more clear the arguments $apply and $digest. My advise is to practice a bit with them to get the concept even clearer.
🙂

LEAVE A REPLY

you might also like