0

I'm using a simple script to geocode addresses.

var geocoder;
var departure;
var arrival;

function initialize() {
    geocoder = new google.maps.Geocoder();
}

google.maps.event.addDomListener(window, 'load', initialize);

function geocode(options) {
    var address = options.address.val() || null;
    var result = {};
    if (address) {
        geocoder.geocode( { 'address': address }, function(results, status) {
            if (status == google.maps.GeocoderStatus.OK) {
                result.lat = results[0].geometry.location.lat();
                result.lng = results[0].geometry.location.lng();
            } else {
                result.lat = null;
                result.lng = null;
            }
        });
    }
}

function geocode_all() {
    departure = geocode({
        address: $('#departure')
    });
    //console.log(departure);

    arrival = geocode({
        address: $('#arrival')
    });
    //console.log(arrival);
}

I would like that my departure variable and my arrival variable to be object with the resulting latitude and longitude.

How should I proceed as my result variable is out of scope?

Thanks !

  • You could have a look at the promises pattern, which would fit your requirements here, I think. – Sirko Feb 05 '14 at 10:43
  • possible duplicate of [How to return the response from an AJAX call?](http://stackoverflow.com/questions/14220321/how-to-return-the-response-from-an-ajax-call) – kapa Feb 05 '14 at 10:46

1 Answers1

1

The problem isn't that the function is anonymous, and it isn't scope; the problem is that the Google geolocation API is asynchronous. It's impossible for your geocode function to return its result; instead, just like Google's function, it must accept a callback that it calls back with the result later, when the result is known. (Or it can use callbacks indirectly, via the "promise" pattern, but the fundamental concept is the same.)

So, using a callback:

function geocode(options, callback) {
    //                    ^--- Accept the callback
    var address = options.address.val() || null;
    var result = {};
    if (address) {
        geocoder.geocode( { 'address': address }, function(results, status) {
            if (status == google.maps.GeocoderStatus.OK) {
                result.lat = results[0].geometry.location.lat();
                result.lng = results[0].geometry.location.lng();
            } else {
                result.lat = null;
                result.lng = null;
            }
            callback(result); // <== Call it
        });
    }
}

// usage
geocode({/*...*/}, function(result) {
    // This gets called later, asynchronously, with the result
});

Or using a jQuery Deferred/Promise:

function geocode(options) {
    var d = new $.Deferred(); // <== Create the deferred
    var address = options.address.val() || null;
    var result = {};
    if (address) {
        geocoder.geocode( { 'address': address }, function(results, status) {
            if (status == google.maps.GeocoderStatus.OK) {
                result.lat = results[0].geometry.location.lat();
                result.lng = results[0].geometry.location.lng();
            } else {
                result.lat = null;
                result.lng = null;
            }
            // Resolve the Deferred using your result
            d.resolve(result);
        });
    }

    // Return the Promise for the Deferred
    return d.promise();
}

// Usage
geocode({/*....*/}).done(function(result) {
    // This gets called later, asynchronously, with the result
});
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875