AngularJs apply explained
·If you’re working on Angularjs apps and getting $digest
in progress or similar errors time to time, it means that you still need to know more about AjngularJs apply functionality and syncing your asynchronous calls with AngularJs properly.
While $apply
and $digest
concept are described very well in AngularJs documents, here I just share my experiments. As a rule of thumb you rarely need to call $apply (and almost never $digest except special cases like unit testing). The common usage of $apply
would be the time you need to sync external DOM events like XHR or 3rd party libraries with your AngularJs app. If you see you are calling $apply
many time in your app here and there, in most cases there is something wrong with your code and you need to fix it.
What $apply
does?
This is a very simple function that force AngularJs to run $digest
and trigger all listeners and watchers about new changes in their scopes.
Proper usage:
This is how you would normally call this function:
1
2
3
$scope.$apply (function () {
$scope.someVariable = 'changed';
});
And if you miss it your app is most probably does not get informed about changes and might cause out-of-sync model updates.
Why is there an error?
This error means you’ve tried to call $apply
in a scope where another $apply
is still in progress. It’s time to revise your code. for example this code would generate error:
1
2
3
4
5
$http.get (url).success (function (result) {
$scope.$apply (function () {
$scope.newValue = result;
});
});
Because all AngularJs modules (in most cases) keep their changes inside $apply
to keep it in sync. Meaning that the above ‘success’ call back would be called within $apply
itself. You don’t need to (and you can’t) do that again.
When to call $apply?
Most of usual and common asynchronous DOM functionalities like window, timeout, Ajax calls and … are already provided as AngularJs modules and they in sync with it (ie. $window
, $timeout
, $http
). But still there is some cases that you need to call this function.
Recently I was working on a project which is using AngularJs and Facebook API and because Facebook API library is asynchronous, I was having difficulties to keep them in sync. Obviously this is one of rare cases that you need to use $apply
.
Let’s see this in a simple example, while this example could be in AngularJs way and not using $apply
, but I just write it in the way that it needs to call $apply
. (this example is not a good practice).
1
2
3
4
5
6
7
angularApp.controller ('ExampleCrtl', [$scope, function ($scope) {
window.setTimeout (function () {
$scope.$apply (function () {
$scope.somethingChanged = "I'm changed";
});
}, 1000);
}]);
And just for clarification here is the same example in AngularJs way:
1
2
3
4
5
6
angularApp.controller ('ExampleCrtl', ['$scope', '$timeout',
function ($scope, $timeout) {
$timeout (function () {
$scope.somethingChanged = "I'm changed";
}, 1000);
}]);