AngularJS and scope.$apply

If you’ve written a non-trivial amount of code in AngularJS, you may have come across the $scope.$apply() method. On the surface, it may seem like just a method you call to get your bindings to update. But why does it exist? And when do you need to use it?

To really understand when to use $apply, it’s good to know exactly why we need to use it, so let’s dive in!

JavaScript is Turn Based

The JavaScript code we write doesn’t all run in one go, instead it executes in turns. Each of these turns runs uninterupted from start to finish, and when a turn is running, nothing else happens in our browser. No other JavaScript code runs, and our web page interface is completely frozen. This is why poorly coded JavaScript can freeze a web page.


Let’s look at an example JavaScript file:

var button = document.getElementById('clickMe');

function buttonClicked () {
  alert('the button was clicked');

button.addEventListener('click', buttonClicked);

function timerComplete () {
  alert('timer complete');

setTimeout(timerComplete, 2000);


If the browser detects a click on #clickMe, it creates a new turn, which executes thebuttonClicked function. When that function returns, that turn is complete.

After 2000 milliseconds, the browser creates a new turn which calls timerComplete.


How do we update bindings?


There are a few solutions. The code needs to know when a value has changed. Right now there is no way for our code to be directly notified of changes on an object1. Instead there are two main strategies.

One strategy is to use special objects, where data is set via methods, not property assignments. Then changes can then be noted, and the page can be updated. This has the downside in that we must extend some special object. Also, for assigning, we must use a more verbose form obj.set('key', 'value') instead of obj.key = 'value'. Frameworks like EmberJS and KnockoutJS use this strategy.

AngularJS takes a different approach: allow any value to be used as a binding target. Then at the end of any JavaScript code turn, check to see if the value has changed. This may seem inneficient at first, but there are some clever strategies to reduce the performance hit. The big benefit is we can use normal objects and update our data however we want, and the changes will be noticed and reflected in our bindings.


$apply and $digest

That step that checks to see if any binding values have changed actually has a method, $scope.$digest(). That’s actually where the magic happens, but we almost never call it directly, instead we use $scope.$apply() which will call$scope.$digest() for you.



You do need to use it if you are going to run code in a new turn. And only if that turn isn’t being created from a method in the AngularJS library. Inside that new turn, you should wrap your code in $scope.$apply(). Here is an example. We are usingsetTimeout, which will execute a function in a new turn after a delay. Since Angular doesn’t know about that new turn, the update will not be reflected.

function Ctrl($scope) {
  $scope.message = "Waiting 2000ms for update";

    setTimeout(function () {
        $scope.message = "Timeout called!";
        // AngularJS unaware of update to $scope
    }, 2000);

But, if we wrap the code for that turn in $scope.$apply(), the change will be noticed, and the page is updated.

function Ctrl($scope) {
  $scope.message = "Waiting 2000ms for update";

    setTimeout(function () {
        $scope.$apply(function () {
            $scope.message = "Timeout called!";
    }, 2000);

As a convenience, AngularJS provides $timeout, which is like setTimeout, but automatically wraps your code in $apply by default. Use that, not this

If you write any code that uses Ajax without $http, or listens for events without using Angular’s ng-* listeners, or sets a timeout without $timeout, you should wrap your code in $scope.$apply

$scope.$apply() vs $scope.$apply(fn)

Sometimes I see examples where data is updated, and then $scope.$apply() is called with no arguments. This achieves the desired result, but misses some opportunities.

If your code isn’t wrapped in a function passed to $apply, and it throws an error, that error is thrown outside of AngularJS, which means any error handling being used in your application is going to miss it. $apply not only runs your code, but it runs it in atry/catch so your error is always caught, and the $digest call is in a finally clause, meaning it will run regardless of an error being thrown. That’s pretty nice.

Hopefully now you understand what $apply is and when to use it. If you only use what AngularJS provides you, you shouldn’t need to use it often. But if you begin writing directives where you are observing DOM elements directly, it is going to become necessary.

  1. Object.observe has been proposed for ES5, but is only experimentally implemented now

Copy from


Leave a Reply


You are commenting using your account. Log Out / Change )

Twitter picture


Facebook photo


Google+ photo


Connecting to %s