Understanding Angular’s $apply() and $digest()

By Sandeep Panda

$apply() and $digest() are two core, and sometimes confusing, aspects of AngularJS. To understand how AngularJS works one needs to fully understand how $apply() and $digest() work. This article aims to explain what $apply() and $digest() really are, and how they can be useful in your day-to-day AngularJS programming.

$apply and $digest Explored

AngularJS offers an incredibly awesome feature known as two way data binding which greatly simplifies our lives. Data binding means that when you change something in the view, the scope model automagically updates. Similarly, whenever the scope model changes, the view updates itself with the new value. How does does AngularJS do that? When you write an expression ({{aModel}}), behind the scenes Angular sets up a watcher on the scope model, which in turn updates the view whenever the model changes. This watcher is just like any watcher you set up in AngularJS:

$scope.$watch('aModel', function(newValue, oldValue) {
  //update the DOM with newValue

The second argument passed to $watch() is known as a listener function, and is called whenever the value of aModel changes. It is easy for us to grasp that when the value of aModel changes this listener is called, updating the expression in HTML. But, there is still one big question! How does Angular figure out when to call this listener function? In other words, how does AngularJS know when aModel changes so it can call the corresponding listener? Does it run a function periodically to check whether the value of the scope model has changed? Well, this is where the $digest cycle steps in.

It’s the $digest cycle where the watchers are fired. When a watcher is fired, AngularJS evaluates the scope model, and if it has changed then the corresponding listener function is called. So, our next question is when and how this $digest cycle starts.

The $digest cycle starts as a result of a call to $scope.$digest(). Assume that you change a scope model in a handler function through the ng-click directive. In that case AngularJS automatically triggers a $digest cycle by calling $digest(). When the $digest cycle starts, it fires each of the watchers. These watchers check if the current value of the scope model is different from last calculated value. If yes, then the corresponding listener function executes. As a result if you have any expressions in the view they will be updated. In addition to ng-click, there are several other built-in directives/services that let you change models (e.g. ng-model, $timeout, etc) and automatically trigger a $digest cycle.

So far, so good! But, there is a small gotcha. In the above cases, Angular doesn’t directly call $digest(). Instead, it calls $scope.$apply(), which in turn calls $rootScope.$digest(). As a result of this, a digest cycle starts at the $rootScope, and subsequently visits all the child scopes calling the watchers along the way.

Now, let’s assume you attach an ng-click directive to a button and pass a function name to it. When the button is clicked, AngularJS wraps the function call within $scope.$apply(). So, your function executes as usual, change models (if any), and a $digest cycle starts to ensure your changes are reflected in the view.

Note: $scope.$apply() automatically calls $rootScope.$digest(). The $apply() function comes in two flavors. The first one takes a function as an argument, evaluates it, and triggers a $digest cycle. The second version does not take any arguments and just starts a $digest cycle when called. We will see why the former one is the preferred approach shortly.

When Do You Call $apply() Manually?

If AngularJS usually wraps our code in $apply() and starts a $digest cycle, then when do you need to do call $apply() manually? Actually, AngularJS makes one thing pretty clear. It will account for only those model changes which are done inside AngularJS’ context (i.e. the code that changes models is wrapped inside $apply()). Angular’s built-in directives already do this so that any model changes you make are reflected in the view. However, if you change any model outside of the Angular context, then you need to inform Angular of the changes by calling $apply() manually. It’s like telling Angular that you are changing some models and it should fire the watchers so that your changes propagate properly.

For example, if you use JavaScript’s setTimeout() function to update a scope model, Angular has no way of knowing what you might change. In this case it’s your responsibility to call $apply() manually, which triggers a $digest cycle. Similarly, if you have a directive that sets up a DOM event listener and changes some models inside the handler function, you need to call $apply() to ensure the changes take effect.

Let’s look at an example. Suppose you have a page, and once the page loads you want to display a message after a two second delay. Your implementation might look something like the JavaScript and HTML shown in the following listing.

See the Pen fukyn by Sandeep Panda (@Sandeep92) on CodePen.

By running the example, you will see that the delayed function runs after a two second interval, and updates the scope model message. Still, the view doesn’t update. The reason, as you may have guessed, is that we forgot to call $apply() manually. Therefore, we need to update our getMessage() function as shown below.

See the Pen bEmBn by Sandeep Panda (@Sandeep92) on CodePen.

If you run this updated example, you can see the view update after two seconds. The only change is that we wrapped our code inside $scope.$apply() which automatically triggers $rootScope.$digest(). As a result the watchers are fired as usual and the view updates.

Note: By the way, you should use $timeout service whenever possible which is setTimeout() with automatic $apply() so that you don’t have to call $apply() manually.

Also, note that in the above code you could have done the model changes as usual and placed a call to $apply() (the no-arg version) in the end. Have a look at the following snippet:

$scope.getMessage = function() {
  setTimeout(function() {
    $scope.message = 'Fetched after two seconds';
    console.log('message:' + $scope.message);
    $scope.$apply(); //this triggers a $digest
  }, 2000);

The above code uses the no-arg version of $apply() and works. Keep in mind that you should always use the version of $apply() that accepts a function argument. This is because when you pass a function to $apply(), the function call is wrapped inside a try...catch block, and any exceptions that occur will be passed to the $exceptionHandler service.

How Many Times Does the $digest Loop Run?

When a $digest cycle runs, the watchers are executed to see if the scope models have changed. If they have, then the corresponding listener functions are called. This leads to an important question. What if a listener function itself changed a scope model? How would AngularJS account for that change?

The answer is that the $digest loop doesn’t run just once. At the end of the current loop, it starts all over again to check if any of the models have changed. This is basically dirty checking, and is done to account for any model changes that might have been done by listener functions. So, the $digest cycle keeps looping until there are no more model changes, or it hits the max loop count of 10. It’s always good to stay idempotent and try to minimize model changes inside the listener functions.

Note: At a minimum, $digest will run twice even if your listener functions don’t change any models. As discussed above, it runs once more to make sure the models are stable and there are no changes.


I hope this article has clarified what $apply and $digest are all about. The most important thing to keep in mind is whether or not Angular can detect your changes. If it cannot, then you must call $apply() manually.

  • jokeyrhyme

    Great article.

    So we should never call $digest() manually? How is $rootScope.$digest() different to $scope.$digest() ?

    • Sandeep Panda


      Most of the times you won’t need to call $digest() manually. Calling $apply() will trigger a $digest cycle. Now, $rootScope.$digest() starts a $digest cycle at the $rootScope which subsequently visits all the child scopes. On the other hand $scope.$digest() starts a $digest cycle at the current $scope which subsequently visits all of its child scopes.

    • Carlin

      Calling $scope.$apply also triggers a $rootScope.$digest

  • Guilherme Akio Sakae

    Nice Post! I’ve been struggling with these methods for quite a while, it’s clear now. Thanks!

    • Sandeep Panda

      Glad to know the article helped you. Thanks!

  • MBehtemam

    in some scenario i’m using $rootScope.broadcast() and event emitter for telling view and controller something changed.for example some thing change in custom service. is it better to use $apply() for this scenario in service or broadcast an

  • David Gonzalez Shannon

    Thanks Sandeep! I get it now. But has anyone had problems with $scope.$apply() feeling really slow? I’m creating an app in angular and jquery, and sometimes I have to update angular models in the jquery events, and each time I call $scope.$apply() from a jquery event it seems like it slows my app down a lot, specially on apple devices. Should I use $scope.$digest() instead? Would it be faster?

    • Sandeep Panda

      Hi David,

      The problem with calling $scope.$digest() directly is that you don’t really know how many scopes you need to $digest in the first place. Your custom directive might be changing some models that come from a scope somewhere up in the scope hierarchy. You don’t know which scope has a watcher for this model. In that case you need to use $apply() because it always starts a $digest() at $rootScope.

      However, if your directive uses an isolated scope and you are sure that some internal models are being changed and should be reflected in the view you can probably just call $digest().

      If calling $apply() causes a lag, you might want to reduce the amount of information presented on the view. May be use ng-view and ng-include so that unnecessary things get destroyed when not in use.

      Hope this helps!

      • TheJeebus

        That doesn’t make sense to me. $digest deals with the scope it’s invoked on, and children. When do you ever update your model that would affect parent scopes? If that happens, it’s IMO spaghetti code.

        • leon

          Think of this case: you have a service that contains some shared state, say MyBasket. Now you might have a widget high in your scope hierarchy that displays the total items in the basket, while some kind of “add/remove item” controls exist in a deeper scope. If your controls modify the basket items, a $digest on their scope will not “notify” the widget.

          • TheJeebus

            Yeah, but that’s just another reason not to have shared state.

            I guess they wanted to “just work” for people, but Angular is too damn slow with any decent amount of data.

  • Sandeep Panda

    I am not sure if I understand your question fully. Can you please ask the question again?

    • Sly Cooper

      What he’s saying is that he sometimes uses $broadcast and $on to send and receive events that would not normally be watched.

      For example, a variable in a service is modified by controller A, but you also want to display the change in DOM within the scope of another controller B and detect it within yet another controller C.

      Controller A would $broadcast a change and controller B would $on receive the change, and the $on callback function would set some local scope variable that is bound using {{}} to the local scope’s DOM. Controller C would also receive the event using $on and do whatever it wants with it.

      To be honest, I’m not sure whether it is better to transmit unwatched changes between scopes or objects using $broadcast, or something like $watch. Broadcasting it would probably be easier, but if you expose the service’s variable, I’m sure you could $watch that variable with a callback to update the local scope as well.

  • Nihar Sawant

    Great. I heard that in case of Ember, it does not do dirty checking. Unlike AngularJS where all watchers are called on when any scope changes, EmberJS calls watcher only for a respective scope. It would be great if you can investigate it.


  • chris_gunawardena

    Thanks! great article Sandeep, I used to think the models had magic setters that fire $apply() on property assignment.

  • Matthias Vandermaesen

    Thanks! This is a very clear explanation of $digest and $apply. Really enjoyed reading this. I imagine that liberal usage of $apply should be avoided if at all possible.

  • CHC

    It is good article

  • Nguyen Kim Son

    Great article Sandeep !

  • shinoj vm

    Great article Sandeep. Thanks!

  • 焦晓东

    Great article. But I have another question need your help:

    As you said, when we change any model outside of the Angular context, we need to call $apply to inform Angular to update the view. However, if the model is bind to a text-box, and the text box value is changed outside of Angular by some JavaScript code. Should we need to call $apply to inform Angular update model value? Or does Angular provide any other API to do this?


    • josh yu

      we need to call $apply or $digest to notify the angular that this model has changed.

  • norbaoliveira

    Thanks for the article! Very good!

  • Diego Eis

    Great article. This explain a lot about the magic behind AngularJS and leave us plan good strategies to scale safely.

  • Luis Alberto Romero Calderon


    why I need to call $apply to tell angular that model has been change? that just call $scope.$digest() directly?

  • Michał Załęcki

    You can call it directly, but in case of using $apply you are able to pass a function as parameter.

  • Vincent Carré

    Thanks for a useful article.

    Do you know of a resource that lists all the AngularJS components that automatically trigger a $digest cycle? (such as ng-click, $timeout…)

  • M’sieur Toph’

    Great post! Very clear.

    But it would be really perfect to talk about the main pb when using $apply/$digest : trying to launch a digest cycle while another one is already running … At the beginning, this error really turned me crazy before I understood how it worked…

  • sparkmorry

    very clear explanation

  • Anand

    Great Article. Thanks

  • stormbytes

    What a terrific writeup! For the many frustrated beginners out there, the quality of Angular’s documentation is running neck-in-neck with the google-translated instructions that came with my second-rate Chinese motherboard. I’ve scoured the web for articles, tutorials and the odd tidbit. This is the first article that conveyed the information concisely, progressively development the relevant ideas and concept. Were Sandeep Panda to write a book on Angular, I’d count myself amongst early adopters. Thanks Sandeep!

  • vishal thakur

    great article..explains clearly. thanks!

  • Christian Alfoni Jørgensen

    Hi Sandeep and thanks for a great article. Do you know btw, why Angular UI events, $timeout and $http triggers the digest cycle differently? An ng-click runs $scope.$$phase = $apply during the ng-click method. $http runs $scope.$$phase = $digest during the callback and $timeout actually has $scope.$$phase = null. So in a $timeout callback you can actually run $scope.$apply() and it does not give an error. This is not very consistent and I am trying to figure out why Angular works this way. Do you have any thoughts on that?

  • weipeng

    Great Article!
    Thank you Sandeep!
    You gave me very clear understand about apply and watch of AngularJS.

    I’m getting this error when I call the scope.$apply() function in my javascript code.
    Error: $apply already in progress

    Please kindly share your time for explain this my problem. Thanks in advance.

    • diwakar

      Please check this before you apply the scope.$apply()
      if(!$rootScope.$$phase) {
      The reason is you might have already triggered the scope.$apply()

      • weipeng

        Thank you.
        It works.

  • Summer Sun

    “You can call it directly, but in case of using $apply you are able to pass a function as parameter.” Is there any other difference between $digest and $appply besides this?

  • Jesus

    …what about a TLDR version??

  • Reza Rahmati

    Very good and clear article.

  • o4hu

    Hmm… As a test for myself, here we go (please feel free to correct):

    1. Model is created in a view, one way data-binding set up between {{myModel}} and $scope.myModel .

    2. How does this work? How do we know when $scope.myModel has changed and trigger an update on {{myModel}}?

    3. Answer: Angular has attached $scope.$watch to $scope.myModel with a callback that will return any changes to $scope.myModel.

    4. But… A change to $scope.myModel may affect other models. To manage this, Angular implements the $digest cycle (I suppose you could say that Angular is ‘digesting’ all of the changes).

    5. The $digest cycle is triggered by certain built-in events (i.e. changes to a model in the view) or you can trigger it explicitly using $scope.$apply(). It may be necessary to call $scope.$apply explicitly under certain conditions (e.g. If you’re using setTimeout()).

    6. The $digest cycle executes all of the $scope.$watch functions to see if any of the models have changed and updates views accordingly. Since some models may affect others, it repeats this process until no $watch functions are reporting any changes (this is called ‘dirty checking’ ) or it has been run 10 times at which point an exception will be thrown.

    • Freddy

      Nice summary. Thanks

  • Improcket

    Very good article , it helped me a lot. Thank you

  • Goldwynn

    This is an awesome article. Thanks Sandeep. I ran into issue of not updating the model in DOM automatically. All are cleared up now.

  • Nameless

    $digest will only fire watchers on the scope from which it is called. That means if you have multiple scopes on the page and you’re absolutely sure you only changed one particular scope’s model, then you can run $digest on that scope and it’ll only fire watchers for that scope and no other ones.

    As firing watchers takes time, you can optimize the performance of your application by reducing the amount of time watchers are fired unnecessarily.

    Apply will go all the way down to the rootscope and fire everything.

  • Vipula S

    Great write up :) Thanks

  • Vishwam

    Great article, Thank you.This has cleared my doubts and made it clear why watches are not getting fired in my code.

  • Srinivas adari

    Great explanation, thank you for posting such a great article here..

  • Cesar

    Very informative, thank you very much!

  • KristofDM

    Thanks for the writeup! Exactly what I was looking for.

  • aluri sudheer

    Awesome article Sandeep, Now I was very cleared about the $apply and $digest and also realized that they are the key feature for two way binding in angularjs.

  • Iain M

    The example really cleared things up for me, thanks!

  • Amrinder Singh

    Wonderful article…. Precise and simple.. Thanks a lot it helped me in understanding these things very well.

    Thumbs up to you..!!

  • Nandu S

    thank you for the great article. It is very useful in understanding $apply behavior.

    I have been trying your sample code with the following change:

    $scope.getMessage = function() {
    window.addEventListener(“message”, function (){
    $scope.$apply(function() {
    $scope.message = ‘Fetched after 3 seconds’;
    } , false);


    I can confirm that the “message” event is received and the event handler function is called, but the page never gets updated with the message.
    Am I missing anything here?

    Thanks in advance for your help

  • Apurva Singh

    Exactly what I was looking for.. Thx!

  • Nitish Kasar

    Thanks alot , Sandeep Awesome explanation on $apply and $digest one of the painful concepts in Angular JS but not after reading this article . Keep it Up

  • Anton Malinin
    • OphelieLechat

      Yikes, looks like it. Thanks Anton, I’ll chase it up.

  • Tin Le

    Thanks, the article is what I’m looking for!

  • Vital Chorniy

    Awesome article, thanks!

  • Muhammad Raza

    Nice article…. THanks

  • Jason Hornbuckle

    excellent article! very clear explanations.

  • Sonam Kansal

    Crisp and Clear. Unambiguous explanation of the topic which makes the concept crystal clear. HatsOff!!

  • TweetsOfSumit

    Great writeup, thank you!

  • Ankit Agarwal

    Excellent Bro!!! 5 starts to you …

  • Maloth Naresh

    Hi Sandeep,
    I might not have understood it correctly, but I got a doubt, lets assume I changed single model of a particular scope. And, I don’t want to watch every model of my scope. Do you think it is possible? (My understanding is : when $digest() is triggered, it lets watcher watch every model of my scope or rootScope). Could you please clear my doubt?

    • Debajit Majumder

      As far as I understood from this article and above comments, this is not possible to watch a single model of the scope with $digest(), it will dirty check all the models in the watch list. Ok, you can optimise little bit by calling $scope.$digest() instead of $scope.$apply() if you are sure that your model will not update any other model in any other scope.
      $scope.$apply() calls $rootScope.$digest(). As a result of this, a digest cycle starts at the $rootScope, and subsequently visits all the child scopes calling the watchers along the way.

  • Cristian Escudero

    Neat article. Quite clear and easy to follow. Thanks.

  • Bimal Das

    Wow.. Nice Post… Thanks

  • Sung Kim

    Great article!

  • smagic39

    many thanks, that is i need !

  • nadistro

    Thank you for clearly explained article !

  • Silambarasan

    superb. Thank you very much for this

  • Diego Timido

    This was dope! Very clear, clean and coherent explanation

  • searching4business

    it sure does explain alot!

  • Piyush Beli

    I must say that this is an awesome post. It makes all the scope concept very clear.
    Thanks for the amazing work.

  • ismail baig

    Beautifully explained. Keep it going . you rock

  • Reuven Karasik

    Such an amazing and helpful article! Thank you :)

  • Emre Demir

    Very helpful and informative article. Thank you.

  • Hasanuzzaman shozib

    Really Nice Article to understand complex think.

  • Raghu G

    its really helped me to understand $apply() & $digest clearly with nice examples… Thanks a lot Sandeep J :-)

  • mohamed idris

    Its the good article can able to easily pickup..

  • Amarjit

    Awesome explanation

  • naresh vadlakonda

    great Article to understand complex think.thank you very much

  • Diwakar kumar jha

    Such nice and clear article…Thank you so much.

  • Jag

    This is a great write up. Keep up your good work. I came across another resource on Angularjs digest cycle here: Hopefully, it helps future readers.



Learn Coding Online
Learn Web Development

Start learning web development and design for free with SitePoint Premium!

Get the latest in JavaScript, once a week, for free.