$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.
$scope.$apply() takes a function or an Angular expression string, and executes it, then calls
$scope.$digest() to update any bindings or watchers.
So, when do you need to call
$apply()? Very rarely, actually. AngularJS actually calls almost all of your code within an $apply call. Events like
ng-click, controller initialization,
$http callbacks are all wrapped in
$scope.$apply(). So you don’t need to call it yourself, in fact you can’t. Calling $apply inside $apply will throw an error.
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 using
setTimeout, 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.
But, if we wrap the code for that turn in
$scope.$apply(), the change will be noticed, and the page is updated.
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() 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 a
try/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.