views:

540

answers:

2

I have a function that is set up as follows

function mainFunction() {
      function subFunction() {
            var str = "foo";
            return str;
      }
}

var test = mainFunction();
alert(test);

To my logic, that alert should return 'foo', but instead it returns undefined. What am I doing wrong?

UPDATE: Here's my actual code (it's a function for reverse-geocoding with the Google API)

function reverseGeocode(latitude,longitude){
    var address = "";
    var country = "";
    var countrycode = "";
    var locality = "";

    var geocoder = new GClientGeocoder();
    var latlng = new GLatLng(latitude, longitude);

     return geocoder.getLocations(latlng, function(addresses) {
     address = addresses.Placemark[0].address;
     country = addresses.Placemark[0].AddressDetails.Country.CountryName;
     countrycode = addresses.Placemark[0].AddressDetails.Country.CountryNameCode;
     locality = addresses.Placemark[0].AddressDetails.Country.AdministrativeArea.SubAdministrativeArea.Locality.LocalityName;
     return country;
    });   
   }
+6  A: 

you have to call a function before it can return anything.

function mainFunction() {
      function subFunction() {
            var str = "foo";
            return str;
      }
      return subFunction();
}

var test = mainFunction();
alert(test);

Or:

function mainFunction() {
      function subFunction() {
            var str = "foo";
            return str;
      }
      return subFunction;
}

var test = mainFunction();
alert( test() );

for your actual code. The return should be outside, in the main function. The callback is called somewhere inside the getLocations method and hence its return value is not recieved inside your main function.

function reverseGeocode(latitude,longitude){
    var address = "";
    var country = "";
    var countrycode = "";
    var locality = "";

    var geocoder = new GClientGeocoder();
    var latlng = new GLatLng(latitude, longitude);

    geocoder.getLocations(latlng, function(addresses) {
     address = addresses.Placemark[0].address;
     country = addresses.Placemark[0].AddressDetails.Country.CountryName;
     countrycode = addresses.Placemark[0].AddressDetails.Country.CountryNameCode;
     locality = addresses.Placemark[0].AddressDetails.Country.AdministrativeArea.SubAdministrativeArea.Locality.LocalityName;
    });   
    return country
   }
z33m
I've updated my question with the actual code. The problem I have is that I'm working with the Google API and so my sub-function is being called by one of their functions. Any ideas how I would get around it?
Chris Armstrong
Thanks. The problem there is that when I simply put return country; it returns " ", because I usually haven't received the info back from Google quick enough. Is there a way of getting it to wait until the value changes?
Chris Armstrong
@chris i think the better way to use these APIs is to put your logic (the stuff that you'd like to do with the country, address ..) inside the callback.
z33m
+2  A: 

Right. The function you pass to getLocations() won't get called until the data is available, so returning "country" before it's been set isn't going to help you.

The way you need to do this is to have the function that you pass to geocoder.getLocations() actually do whatever it is you wanted done with the returned values.

Something like this:

function reverseGeocode(latitude,longitude){
  var geocoder = new GClientGeocoder();
  var latlng = new GLatLng(latitude, longitude);

  geocoder.getLocations(latlng, function(addresses) {
    var address = addresses.Placemark[0].address;
    var country = addresses.Placemark[0].AddressDetails.Country.CountryName;
    var countrycode = addresses.Placemark[0].AddressDetails.Country.CountryNameCode;
    var locality = addresses.Placemark[0].AddressDetails.Country.AdministrativeArea.SubAdministrativeArea.Locality.LocalityName;
    do_something_with_address(address, country, countrycode, locality);
  });   
}

function do_something_with_address(address, country, countrycode, locality) {
  if (country==="USA") {
     alert("USA A-OK!"); // or whatever
  }
}

If you might want to do something different every time you get the location, then pass the function as an additional parameter to reverseGeocode:

function reverseGeocode(latitude,longitude, callback){
  // Function contents the same as above, then
  callback(address, country, countrycode, locality);
}
reverseGeocode(latitude, longitude, do_something_with_address);

If this looks a little messy, then you could take a look at something like the Deferred feature in Dojo, which makes the chaining between functions a little clearer.

Mark Bessey
Thanks, the problem I have however is that I'm wanting to use the reverseGeocode several times throughout my code. I have a list of status updates and their locations returned from the twitter API, and so am wanting to call reverseGeocode for each one. Also, I'm wanting to call reverseGeocode for the current user's location.Not sure if that makes sense... the site is at http://www.chris-armstrong.com/whispers if you want to take a look and see what I mean
Chris Armstrong
When in doubt, use more functions:-) See edits above...
Mark Bessey