Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AngularJS: geolocation + promise + $apply

I have some problems using the geolocation AngularJS plugin https://github.com/arunisrael/angularjs-geolocation/blob/master/src/geolocation.js.

When you look at line 17, an $apply is called. This seems ok for me, because the callback of the getCurrentPosition runs async, and out of the scope of angular's digest:

angular.module('geolocation')
  .factory('geolocation', ['$q','$rootScope','$window','geolocation_msgs','$timeout',function ($q,$rootScope,$window,geolocation_msgs,$timeout) {
    return {
      getLocation: function (opts) {
        var deferred = $q.defer();
        if ($window.navigator && $window.navigator.geolocation) {
          $window.navigator.geolocation.getCurrentPosition(function(position){
            $rootScope.$apply(function(){deferred.resolve(position);});
          }

In a normal desktop browser this works fine. But when used inside a PhoneGap app, along with cordovas geolocation plugin (https://github.com/apache/cordova-plugin-geolocation), it throws an $digest already in progress error on iOS7.

So, I did a little bit of debugging, and found out, that the following version works everywhere, on a desktop browser AND inside a PhoneGap app:

angular.module('geolocation')
  .factory('geolocation', ['$q','$rootScope','$window','geolocation_msgs','$timeout',function ($q,$rootScope,$window,geolocation_msgs,$timeout) {
    return {
      getLocation: function (opts) {
        var deferred = $q.defer();
        if ($window.navigator && $window.navigator.geolocation) {
          $window.navigator.geolocation.getCurrentPosition(function(position){
            deferred.resolve(position);
          }

So, I'm a little bit confused.

  1. Is the whole callback still in angular's scope?
  2. If so, why does an $apply call don't throw an $digest already in progress error on my desktop browser?
  3. And if it's not in the scope, why does just a deferred.resolve(position); work? Does this have anything to do with references to the deferred var?
  4. Do I have to wrap the resolve call on a promise (and outside of angulars digest scope) inside an $apply callback?

Hope someone can help me to clear my mind!

like image 377
23tux Avatar asked Aug 04 '26 06:08

23tux


1 Answers

This line:

$rootScope.$apply(function(){deferred.resolve(position);});

Is incorrect. It should just be:

deferred.resolve(position);

Since the deferred comes from $q, it's inside Angulars world. $q is aware of the $rootScope and will call $rootScope.$apply() for you when you resolve a promise. The error you're getting: $digest already in progress is a proof of that. Angular is telling you that there's some part of the code which is calling $apply() twice, which is line 17.

like image 162
Anders Ekdahl Avatar answered Aug 06 '26 20:08

Anders Ekdahl



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!