Stack trace:
Error: $apply already in progress
at Error ()
at beginPhase (file:///android_asset/www/built.min.js:7:22740)
at Object.Scope.$a
I know it's old question but if you really need use $scope.$applyAsync();
In my case i use $apply
with angular calendar UI to link some event:
$scope.eventClick = function(event){
$scope.$apply( function() {
$location.path('/event/' + event.id);
});
};
After reading the doc of the problem: https://docs.angularjs.org/error/$rootScope/inprog
The part Inconsistent API (Sync/Async) is very interesting:
For example, imagine a 3rd party library that has a method which will retrieve data for us. Since it may be making an asynchronous call to a server, it accepts a callback function, which will be called when the data arrives.
Since, the MyController constructor is always instantiated from within an $apply call, our handler is trying to enter a new $apply block from within one.
I change the code to :
$scope.eventClick = function(event){
$timeout(function() {
$location.path('/event/' + event.id);
}, 0);
};
Works like a charm !
Here we have used $timeout to schedule the changes to the scope in a future call stack. By providing a timeout period of 0ms, this will occur as soon as possible and $timeout will ensure that the code will be called in a single $apply block.
In angular 1.3, I think, they added a new function - $scope.$applyAsync()
. This function calls apply later on - they say about 10 ms later at least. It is not perfect, but it does at least eliminate the annoying error.
https://docs.angularjs.org/api/ng/type/$rootScope.Scope#$applyAsync
I call $scope.$apply like this to ignored call multiple in one times.
var callApplyTimeout = null;
function callApply(callback) {
if (!callback) callback = function () { };
if (callApplyTimeout) $timeout.cancel(callApplyTimeout);
callApplyTimeout = $timeout(function () {
callback();
$scope.$apply();
var d = new Date();
var m = d.getMilliseconds();
console.log('$scope.$apply(); call ' + d.toString() + ' ' + m);
}, 300);
}
simply call
callApply();
If scope must be applied in some cases, then you can set a timeout so that the $apply is deferred until the next tick
setTimeout(function(){ scope.$apply(); });
or wrap your code in a $timeout(function(){ .. }); because it will automatically $apply the scope at the end of execution. If you need your function to behave synchronously, I'd do the first.