Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I use a deferred object to retrieve a longitude and latitude with the HTML5 Geolocation API?

I'd like to use the HTML5 GeoLocation API to retrieve my longitude and latitude and manage the request using a jQuery Deferred object.

Here is what my code looks like:

var geoLocation = {

    getLocation: function() {

        // create deferred object
        var deferred = $.Deferred();

        // if geo location is supported
        if(navigator.geolocation) {

            // get current position and pass the results to this.geoLocationSuccess or time out after 5 seconds if it fails
            navigator.geolocation.getCurrentPosition(this.geoLocationSuccess, this.geoLocationError, {
                timeout: 5000
            });

        } else {

            // geo location isn't supported
            console.log('Your browser does not support Geo Location.');
        }

    },

    geoLocationSuccess: function(position) {

        // resolve deffered object
        deferred.resolve(position.coords.latitude, position.coords.longitude);

        // return promise
        return deferred.promise();
    },

    geoLocationError: function() {
        console.log('Geo Location failed.');
    }

};

And here is my Deferred object:

$.when(geoLocation.getLocation()).then(function(data, textStatus, jqXHR) {

    console.log(data);

});

I'm expecting the longitude and latitude to be returned by the then() callback but instead, I get the error that deferred is undefined. I think it has something to do with the scope of where I define my deferred object but I'm not sure. What am I missing?

like image 683
Michael Lynch Avatar asked Feb 11 '23 23:02

Michael Lynch


1 Answers

Michael, after reading Hackaholic's answer and your own, both will work with regard to handling successfully returned data, but errors could be better handled.

If navigator.geolocation.getCurrentPosition() fails, it will pass a potentially informative PositionError object to its error handler. This object, which can be passed down the promise chain and handled in the calling function, is disregarded in both answers.

Similarly, promise rejection can also be used to pass your own "Your browser does not support Geo Location" error down the promise chain.

var geoLocation = {
    getLocation: function() {
        var deferred = $.Deferred();
        if(navigator.geolocation) {
            // geo location is supported. Call navigator.geolocation.getCurrentPosition and :
            // - resolve the promise with the returned Position object, or
            // - reject the promise with the returned PositionError object, or
            // - time out after 5 seconds
            navigator.geolocation.getCurrentPosition(deferred.resolve, deferred.reject, { timeout: 5000 });
        } else {
            //geo location isn't supported
            //Reject the promise with a suitable error message
            deferred.reject(new Error('Your browser does not support Geo Location.'));
        }
        return deferred.promise();
    } 
};

Ignoring the comments, this is very compact and note how geoLocation.getLocation() makes no attempt to handle errors but makes them available to the calling function's error handler.

Now, $.when() is not necessary because your geoLocation.getLocation() function returns a promise which has its own .then() method. It is already "thenable" without $.when().

geoLocation.getLocation().then(function(position) {
    console.dir(position);
}).fail(function(err) {
    console.error(err);
});

Thus, you fully exploit the ability of the promise to handle success or failure.

like image 104
Roamer-1888 Avatar answered Feb 14 '23 23:02

Roamer-1888