Trace de la pile:
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
fait référence à ce code http://Pastebin.com/B9V6yvF
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
});
})
Chose étrange, cela fonctionne bien sur mon LG4X, mais sur mon samsung s2, l'erreur ci-dessus est générée. Des idées ce qui ne va pas?
Vous obtenez cette erreur parce que vous appelez $apply
dans un cycle de digestion existant.
La grande question est: pourquoi appelez-vous $apply
? Vous ne devriez jamais avoir besoin d'appeler $apply
à moins que vous n'interfaciez depuis un événement non angulaire. L'existence de $apply
signifie généralement que je fais quelque chose de mal (à moins que, encore une fois, le $ apply se produise à partir d'un événement non angulaire).
Si $apply
est vraiment approprié ici, envisagez d'utiliser une approche "d'application sans danger":
Utilisez simplement $ evalAsync au lieu de $apply
.
Vous pouvez utiliser cette déclaration:
if ($scope.$root.$$phase != '$apply' && $scope.$root.$$phase != '$digest') {
$scope.$apply();
}
Si la portée doit être appliquée dans certains cas, vous pouvez définir un délai d'attente de sorte que le $ apply soit différé jusqu'au prochain tick
setTimeout(function(){ scope.$apply(); });
ou envelopper votre code dans un $ timeout (function () {..}); car $ appliquera automatiquement la portée à la fin de l’exécution. Si vous avez besoin que votre fonction se comporte de manière synchrone, je ferais la première.
Dans angular 1.3, je pense qu'ils ont ajouté une nouvelle fonction - $scope.$applyAsync()
. Les appels de fonction s’appliquent plus tard - ils disent au moins 10 ms plus tard. Ce n'est pas parfait, mais au moins cela élimine l'erreur ennuyeuse.
https://docs.angularjs.org/api/ng/type/ $ rootScope.Scope # $ applyAsync
Dans mon cas, j'utilise $apply
avec angular interface de calendrier pour lier un événement:
$scope.eventClick = function(event){
$scope.$apply( function() {
$location.path('/event/' + event.id);
});
};
Après avoir lu la documentation du problème: https://docs.angularjs.org/error/ $ rootScope/inprog
La partie API Inconsistent (Sync/Async) est très intéressante:
Par exemple, imaginez une bibliothèque tierce qui possède une méthode permettant de récupérer des données pour nous. Dans la mesure où il peut effectuer un appel asynchrone vers un serveur, il accepte une fonction de rappel, qui sera appelée lorsque les données arriveront.
Étant donné que le constructeur MyController est toujours instancié à partir d'un appel $ apply, notre gestionnaire tente de saisir un nouveau bloc $ apply à partir de celui-ci.
Je change le code en:
$scope.eventClick = function(event){
$timeout(function() {
$location.path('/event/' + event.id);
}, 0);
};
Fonctionne comme un charme!
Ici, nous avons utilisé $ timeout pour planifier les modifications apportées à l'étendue dans une future pile d'appels. En fournissant un délai d'expiration de 0 ms, cela se produira dès que possible et $ timeout garantira que le code sera appelé dans un seul bloc $ apply.
À tout moment, il ne peut y avoir qu'une seule opération $digest
ou $apply
en cours. Cela évite très difficilement la détection de bogues dans votre application. La trace de pile de cette erreur vous permet de suivre l'origine de l'appel $apply
ou $digest
en cours d'exécution, à l'origine de l'erreur.
Plus d'infos: https://docs.angularjs.org/error/$rootScope/inprog?p0=$apply
Juste résolu ce problème. Son documenté ici .
J'appelais $rootScope.$apply
deux fois dans le même flux. Tout ce que j'ai fait est encapsulé le contenu de la fonction de service avec un setTimeout(func, 1)
.
Je sais que c'est une vieille question, mais si vous avez vraiment besoin d'utiliser $ scope. $ ApplyAsync ();
J'appelle $ scope. $ S'applique comme ceci aux appels ignorés multiples en une fois.
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);
}
simplement appeler
callApply();