29

How can I use HTML5 geolocation in angularjs? I can get it using HTML5; but how can I pass it to angularjs scope in controller? any sample jsfiddle will save my day!

4 Answers 4

67

I'd suggest abstracting this into a service so your controller doesn't have a dependency on window.navigator, and to avoid the unnecessary use of $scope.$apply(). Here's what I'm using in my project:

angular.module('app', []).factory('geolocationSvc', ['$q', '$window', function ($q, $window) {

    'use strict';

    function getCurrentPosition() {
        var deferred = $q.defer();

        if (!$window.navigator.geolocation) {
            deferred.reject('Geolocation not supported.');
        } else {
            $window.navigator.geolocation.getCurrentPosition(
                function (position) {
                    deferred.resolve(position);
                },
                function (err) {
                    deferred.reject(err);
                });
        }

        return deferred.promise;
    }

    return {
        getCurrentPosition: getCurrentPosition
    };
}]);

Then I consume it in my controller like this:

function captureUserLocation() {
    geolocationSvc.getCurrentPosition().then(onUserLocationFound);
}
Sign up to request clarification or add additional context in comments.

3 Comments

This should be the answer, it promotes decoupling and shows good use of async programming.
Although this is an old posting, I found it very helpful to getting started using geoLocation. Wonder how to test for error and don't understand your onUserLocationFound function above, what handling does it do and how does it handle the error?
@HarveyMushman The implementation returns a promise resolved with the user's position (deferred.resolve(position)), so your handler would be a function receiving that data, e.g. onUserLocationFound(position) { ... }. if you want to handle geolocation errors, you'd use a catch like any other promise.
34

you can do something

myApp.controller('fooCtrl', function($scope){
  if (navigator.geolocation) {
    navigator.geolocation.getCurrentPosition(function(position){
      $scope.$apply(function(){
        $scope.position = position;
      });
    });
  }
})

you need to do $scope.$apply to trigger the digest cycle when the geolocation arrives and to update all the watchers.

3 Comments

can u please help me with jsfiddle?? if u dont mind, i am a newbie to angularjs and havent used watch yet. if not, i wont mind :)
if you create a skeleton jsfiddle or plunkr i can fill this in, but you have to do some of the work yourself
watch your step working with this snippet! in some kind of browsers this returns an security alert and in Chrome(50+) navigator.geolocation is not supported without https!
2

You can use ngGeolocation. It is simple and does the job.

angular.module('appName', ['ngGeolocation'])
    .controller('appCtrl', function($scope, $geolocation) {
         $geolocation.getCurrentPosition().then(function(position) {
            console.log(position, 'current position');
         });
    });

Comments

0

Due to firefox's issue not getting feedback from user on prompting that website needs to access your location when user clicking "Not now", X or outside prompt box (more here), below is a tiny example to trigger fallback action for this case. Plunker

// GeoLocationService
angular.module('myApp').factory('GeoLocationService', function($q, $window, $timeout) {
    var factoryObj = {};

    factoryObj.getPosition = function() {
        var deferred;
        var promiseTimeout = $timeout(function() {
            deferred.reject(1); // return 1 if browser waited for user input for more than timeout delay
        }, 3000);

        deferred = $q.defer();

        if(!$window.navigator.geolocation) { // check if geoLocation is not supported by browser
            $timeout.cancel(promiseTimeout);
            deferred.reject(false); // return false if geoLocation is not supported
        }
        else { // geoLocation is supported
            $window.navigator.geolocation.getCurrentPosition(function(position) {
                $timeout.cancel(promiseTimeout);
                return deferred.resolve(position);
            }, function(error) {
                $timeout.cancel(promiseTimeout);
                return deferred.reject(error.code || 1);
            });
        }

        return deferred.promise;
    };

    return factoryObj;
});

And your app js.

// App
var app = angular.module('myApp', []).controller('myCtrl', function($scope, $log, GeoLocationService) {
    $scope.position = {};

    GeoLocationService.getPosition().then(
        function(position) { // 
            $scope.position = position;
            $log.debug(position);
        },
        function(errorCode) {
            if(errorCode === false) {
                alert('GeoLocation is not supported by browser.');
            }
            else if(errorCode == 1) {
                alert('User either denied GeoLocation or waited for long to respond.');
            }
        }
    );
});

1 Comment

I wouldn't recommend this approach. It's impossible to pick a timeout duration appropriate for all scenarios, and I wouldn't want to preclude geolocation simply because the visitor didn't answer fast enough. Instead, I'd design my user experience to accommodate not having the user's location, regardless of the reason. And if you really DO want this behavior, I wouldn't put it in the geolocation service; it should go in the controller consuming that service.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.