$apply already in progress error
AngularjsCordovaAngularjs DigestAngularjs Problem Overview
Stack trace:
Error: $apply already in progress
at Error (<anonymous>)
at beginPhase (file:///android_asset/www/built.min.js:7:22740)
at Object.Scope.$apply (file:///android_asset/www/built.min.js:7:25967)
at navigator.geolocation.getCurrentPosition.that (file:///android_asset/www/built.min.js:13:8670)
at Object.geolocation.getCurrentPosition (file:///android_asset/www/plugins/org.apache.cordova.core.geolocation/www/geolocation.js:122:13)
at Object.getCurrentPosition (file:///android_asset/www/built.min.js:13:8589)
at Object.getCurrentPosition (file:///android_asset/www/built.min.js:13:8277)
at Object.getCurrentCity (file:///android_asset/www/built.min.js:13:8941)
at Object.$scope.locateDevice (file:///android_asset/www/built.min.js:13:10480)
at file:///android_asset/www/built.min.js:7:12292:7
refers to this code http://pastebin.com/B9V6yvFu
getCurrentPosition: cordovaReady(function (onSuccess, onError, options) {
navigator.geolocation.getCurrentPosition(function () {
var that = this,
args = arguments;
if (onSuccess) {
$rootScope.$apply(function () {
onSuccess.apply(that, args);
});
}
}, function () {
var that = this,
args = arguments;
if (onError) {
$rootScope.$apply(function () {
onError.apply(that, args);
});
}
}, {
enableHighAccuracy: true,
timeout: 20000,
maximumAge: 18000000
});
})
Strange thing, on my LG4X it works fine, however on my samsung s2 it throws the above error. Any ideas whats wrong?
Angularjs Solutions
Solution 1 - Angularjs
You are getting this error because you are calling $apply
inside an existing digestion cycle.
The big question is: why are you calling $apply
? You shouldn't ever need to call $apply
unless you are interfacing from a non-Angular event. The existence of $apply
usually means I am doing something wrong (unless, again, the $apply happens from a non-Angular event).
If $apply
really is appropriate here, consider using a "safe apply" approach:
Solution 2 - Angularjs
Just use $evalAsync instead of $apply
.
Solution 3 - Angularjs
You can use this statement:
if ($scope.$root.$$phase != '$apply' && $scope.$root.$$phase != '$digest') {
$scope.$apply();
}
Solution 4 - Angularjs
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.
Solution 5 - Angularjs
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.
Solution 6 - Angularjs
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
Solution 7 - Angularjs
At any point in time, there can be only one $digest
or $apply
operation in progress. This is to prevent very hard to detect bugs from entering your application. The stack trace of this error allows you to trace the origin of the currently executing $apply
or $digest
call, which caused the error.
More info: <https://docs.angularjs.org/error/$rootScope/inprog?p0=$apply>
Solution 8 - Angularjs
Just resolved this issue. Its documented here.
I was calling $rootScope.$apply
twice in the same flow. All I did is wrapped the content of the service function with a setTimeout(func, 1)
.
Solution 9 - Angularjs
I know it's old question but if you really need use $scope.$applyAsync();
Solution 10 - Angularjs
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();
Solution 11 - Angularjs
We can use setTimeout
function in such cases.
console.log('primary task');
setTimeout(function() {
console.log('secondary task');
}, 0);
This will make sure that secondary task will be executed when execution of primary task is finished.
Solution 12 - Angularjs
You can $apply
your changes only if $apply
is not already in progress. You can update your code as
if(!$scope.$$phase) $scope.$apply();