3

So I have a code here:

.factory("Geolocation", ["$cordovaGeolocation",
  function ($cordovaGeolocation) {
    var posOptions = {
      timeout: 10000,
      enableHighAccuracy: false
    };
    var getCurrentPosition = $cordovaGeolocation.getCurrentPosition(posOptions);
    return {
      lat: function () {
       getCurrentPosition.then(function(position) {
          return position.coords.latitude; //getting undefined  
        })
      },
      long: function() {
       getCurrentPosition.then(function(position) {
          return position.coords.longitude;  
        })
      }
    }

  }
])

And in my controller I call it Geolocation.lat() or Geolocation.long().

Now my problem is that I am getting undefined instead of the lat and long.

If I do something like:

return getCurrentPosition.then(function(position) {
  return position.coords.longitude;  
})

I am getting another promise which is redundant and what I only want to happen is to get the lat and long.

Is there a simple way to access the variables inside of that promise?

Any help would be much appreciated.

UPDATE (tried declaring a variable outside and to be filled inside the promise but I still get a null value.

.factory("Geolocation", ["$cordovaGeolocation", "$rootScope",
  function ($cordovaGeolocation, $rootScope) {
    var posOptions = {
      timeout: 10000,
      enableHighAccuracy: false
    };
    var getCurrentPosition = $cordovaGeolocation.getCurrentPosition(posOptions);
    $rootScope.latitude = null;
    $rootScope.longitude = null;
    return {
      lat: function () {
       getCurrentPosition.then(function(position) {
          $rootScope.latitude = position.coords.latitude;  
        })
        return $rootScope.latitude;
      },
      long: function() {
       getCurrentPosition.then(function(position) {
          return $rootScope.longitude; 
        })
      }
    }

  }
])
wobsoriano
  • 12,348
  • 24
  • 92
  • 162
  • what is `position` / what properties/values does it contain? what is `position.coords`? may it be a promise too? – Thomas Dec 28 '16 at 05:49
  • 1
    `I am getting another promise which is redundant` Promises deal with time. They deal with the fact, that you don't know when `getCurrentPosition` will contain a value for you to use. It may be in 1ms or in 30s, or never. Do you want your code to wait pending that long? Do you want your code/application to freeze for an unspecified period of time? that's why you get another Promise. *"I promise I'll give you an answer as soon as I have one, but I have no idea when this will be. Register here to get notified, so you can continue your task."* That's what a Promise is. – Thomas Dec 28 '16 at 05:58

3 Answers3

3

Since you are doing asynchronous operations the method that you adopted would never work.

Instead what you should do is :

  1. Declare a scope variable outside the promise.
  2. Resolve the promise which is returned by the factory
  3. Assign the declared value to the response.data.

So don't return the then from factory.

Instead just send the promise to the controller.

Then in the controller do the above steps and get the data.

var promise = yourFactory.get() //get the promise
promise.then(function(response){
      $scope.lat = response.data
})
Pritam Banerjee
  • 17,953
  • 10
  • 93
  • 108
  • Tried and I get a null value – wobsoriano Dec 28 '16 at 05:50
  • But how does the client-code know, **when** `$scope.lat` has been filled/set? This way you're neglecting/cancelling everything that promises solve. The main problem promises solve is dealing with async operations and the state of the synchronization. Am I still waiting for response or do I have a result? Or an error? – Thomas Dec 28 '16 at 05:51
  • @FewFlyBy check the service and the parameters. Check if all your syntaxes are correct. – Pritam Banerjee Dec 28 '16 at 05:52
  • Everything is correct and I still can't get it. I guess it's a cordovaGeolocation problem – wobsoriano Dec 28 '16 at 06:42
  • jsfiddle.net/0yt6t5vm/1 – wobsoriano Dec 28 '16 at 07:41
2

I guess you access those variables in synchronous way while your method is asynchronous.

You can not direct access to variable just after calling asynchronous method because your method It's not finish execution yet. You need to access thought promise or callback function.

You came the right way when returning the promise.

long: function() {
   return getCurrentPosition.then(function(position) {
      return position.coords.longitude;  
    })
  }

but your controller need to access the result in the asynchronous's promise way.

Geolocation.long().then(function(longitude){
    alert("Here, I can access it " + longitude)
});
Hereblur
  • 2,084
  • 1
  • 19
  • 22
0

@Hereblur is right. You should just return a promise and use then().

This is a fully working example:

angular
.module("app", ["ngCordova.plugins.geolocation"])
.factory("Geolocation", ["$cordovaGeolocation", function ($cordovaGeolocation) {
            var posOptions = {
                timeout : 10000,
                enableHighAccuracy : false
            };
            var getCurrentPosition = $cordovaGeolocation.getCurrentPosition(posOptions);
            return {
                lat : function () {
                    return getCurrentPosition.then(function (position) {
                        return position.coords.latitude;
                    })
                },
                long : function () {
                    return getCurrentPosition.then(function (position) {
                        return position.coords.longitude;
                    })
                }
            }

        }
    ])
.controller("testCtrl", ["Geolocation", function (Geolocation) {
            Geolocation.lat().then(function (lat) {
                console.log(lat);
            });
            Geolocation.long().then(function (long) {
                console.log(long);
            });
        }
    ]);

jsfiddle with the example

  • 2
    Dude I did this already. I know it's working but I cant access the variable outside of that promise in the controller. – wobsoriano Dec 28 '16 at 07:39
  • https://jsfiddle.net/0yt6t5vm/1/ check this so you know – wobsoriano Dec 28 '16 at 07:40
  • 1
    You can. The only thing you should know is that the callback in then() will not run immediately. The result of then() will not available at the end of the controller execution. Everything that you want to do with latitude and longitude should be put inside then() callback. There is no problem to assign the values to the scope and show them on the vew. https://jsfiddle.net/0yt6t5vm/3/ – Viktar Tserashchuk Dec 28 '16 at 07:56
  • So there is no way to access it outside then. – wobsoriano Dec 28 '16 at 11:28