views:

406

answers:

3

I'm trying to work with the google maps API and am having some trouble. I've created a function called getPoint which accepts an address. It uses the google api to turn that address into a GPoint object using the GClientGeocoder.getLatLng(address,callback) function. The getLatLng() is passed the address and a callback function as you can see below. I want the getPoint() function I've written to return the "point" variable passed to the callback function from the getLatLng() call. I am struggling to figure out how to do this or even if it can be done?

function getPoint(address) {
  var geocoder = new GClientGeocoder();

  return geocoder.getLatLng(
    address,
    function(point){
      return point;
    }
  );
}

Thanks in advance for the help!

+5  A: 

GClientGeocoder.getLatLng is an asynchronous operation, so you cannot have a return statement in getPoint actually do what you expect.

You have to restructure your code to take a callback function, which you call when the asynchronous operation completes:

function getPoint(address, callback) {
    var geocoder = new GClientGeocoder();

    geocoder.getLatLng(
        address,
        function(point){
            /* asynch operation complete.
             * Call the callback with the results */
            callback(point)
        }
    );
}

or even better (albeit a touch more esoteric):

function getPoint(address, callback) {
    var geocoder = new GClientGeocoder();

    geocoder.getLatLng(
        address,
        callback // GClientGeocoder will call the callback for you
    );
}

Edit re your comment question:

OK that is a whole other question, but in a nutshell, the JavaScript function callback you pass will have access to your map instance as long as you define the function in the same scope as the map instance is defined:

var map = new GMap2(/*...*/);
var addresses = []; // list of address strings
for(var i=0; i < addresses.length; i++) {
    getPoint(addresses[i], function(point) { // pass the callback function
        map.addOverlay(/*...*/); // map variable is in scope
    })
}

This style of function is called a closure.

Roatin Marth
Thanks for the great response. This leads me to another problem I think... I have a function called Initialize() which is called onLoad() of the body which creates a GMap2 object. I then do an ajax post to retrieve a list of addresses and then loop through those addresses and one by one create a GPoint object so that I may add a GMarker to the GMap2 for each address. Doesn't the callback function you're saying I should specify need access to that GMap object? If so how do I get that GMap2 object in scope for the callback function?
Ryan
Nevermind, map is in scope not like I thought it wasn't.Thanks!
Ryan
Ah christ, I just typed up a whole response to your comment.
Roatin Marth
A: 

You cannot do this. getLatLng() is an asynchronous function: it will send a HTTP request and invoke the callback once a response is received. Meanwhile, your local script execution will continue and getLatLng() will return before your callback is called.

Ferdinand Beyer
+2  A: 

No, it cannot be done. Instead, you must set up a method that knows what to do with the answer once it arrives at some point in the future--that's the nature of a callback.

So, currently, your design looks like:

var myPoint = getPoint(theAddress);
doSomethingWithPoint(myPoint);
doSomethingElseWithPoint(myPoint);

But now it should look like

function getPoint(address, callback) {
    var geocoder = new GClientGeocoder();
    geocoder.getLatLng(address, callback);
}
getPoint(theAddress, function(myPoint) {
    doSomethingWithPoint(myPoint);
    doSomethingElseWithPoint(myPoint);
});
Jonathan Feinberg
+1; but your anonymous callback function needs a "myPoint" parameter.
RMorrisey
D'oh! Thanks. 15 chars. 15 chars. 15 chars.
Jonathan Feinberg