2

Hi I have a button which when it gets clicked triggers a function. The function does some stuff (reverse geocodes a latitude/longitude) and then fills a hidden form input with a value.

I need the input to have the correct value before the rest of the code I need gets executed, is there a way to do this? At the moment I have

$('.addButton').click(function() { //first run the reverse geocode to update the hidden location input with the readable address reversegeocode(); var location = $("#location").val();//the value I need $.post("<?php echo $this->webroot;?>locations/add", {location:location}) .done(function (data) { $("#locationsHolder").html(data); }); }); 

So basically I don't want to get the value from the input and post it via AJAX until I know that the reversegeocode() function has finished

Can anyone please explain how I can go about this. I've read some stuff about deferment but I'm absolutely useless at figuring out Javascript and I'm really struggling.

Thanks

EDIT:

Here's my reversegeocode funciton

function reversegeocode(){ var lat = $('#lattitude').val(); var lng = $('#longitude').val(); var latlng = new google.maps.LatLng(lat, lng); geocoder.geocode({'latLng': latlng}, function(results, status) { if (status == google.maps.GeocoderStatus.OK) { if (results[0]) {//http://stackoverflow.com/questions/8082405/parsing-address-components-in-google-maps-upon-autocomplete-select var address_components = results[0].address_components; var components={}; jQuery.each(address_components, function(k,v1) {jQuery.each(v1.types, function(k2, v2){components[v2]=v1.long_name});}) var output = ''; var needAcomma = false; if(components.route != undefined) { output += components.route; needAcomma = true; } if(components.locality != undefined) { if(needAcomma) { output += ', '; } output += components.locality; needAcomma = true; } if(components.administrative_area_level_1 != undefined) { if(needAcomma) { output += ', '; } output += components.administrative_area_level_1; needAcomma = true; }else if(components.administrative_area_level_2 != undefined) { if(needAcomma) { output += ', '; } output += components.administrative_area_level_2; needAcomma = true; }else if(components.administrative_area_level_3 != undefined) { if(needAcomma) { output += ', '; } output += components.administrative_area_level_3; needAcomma = true; } $("#location").val(output); } else { alert('No results found'); } } else { alert('Geocoder failed due to: ' + status); } }); } 
2
  • 1
    looks like reversegeocode is an asynchronous method, you need to share that method for us to see what can be done. Any way the reversegeocode method need to provide some kind of callback facility to let us know when it is completed Commented Feb 19, 2014 at 23:35
  • Hi, thanks for the response. I've stuck my function in my question. it just gets the address from google and sticks the result in an input. Commented Feb 20, 2014 at 0:01

4 Answers 4

2

Since reversegeocode is a asynchronous method, you need to use a callback based solution. reversegeocode should receive a callback method as a argument and then invoke the callback once the geocoding is completed.

$('.addButton').click(function () { //pass a callback to reversegeocode which will get called once the geocoding is completed reversegeocode(function (location) { //the callback receives the location as a parameter $.post("<?php echo $this->webroot;?>locations/add", { location: location }) .done(function (data) { $("#locationsHolder").html(data); }); }); }); function reversegeocode(callback) { var lat = $('#lattitude').val(); var lng = $('#longitude').val(); var latlng = new google.maps.LatLng(lat, lng); geocoder.geocode({ 'latLng': latlng }, function (results, status) { if (status == google.maps.GeocoderStatus.OK) { if (results[0]) { //http://stackoverflow.com/questions/8082405/parsing-address-components-in-google-maps-upon-autocomplete-select var address_components = results[0].address_components; var components = {}; jQuery.each(address_components, function (k, v1) { jQuery.each(v1.types, function (k2, v2) { components[v2] = v1.long_name }); }) var output = ''; var needAcomma = false; if (components.route != undefined) { output += components.route; needAcomma = true; } if (components.locality != undefined) { if (needAcomma) { output += ', '; } output += components.locality; needAcomma = true; } if (components.administrative_area_level_1 != undefined) { if (needAcomma) { output += ', '; } output += components.administrative_area_level_1; needAcomma = true; } else if (components.administrative_area_level_2 != undefined) { if (needAcomma) { output += ', '; } output += components.administrative_area_level_2; needAcomma = true; } else if (components.administrative_area_level_3 != undefined) { if (needAcomma) { output += ', '; } output += components.administrative_area_level_3; needAcomma = true; } $("#location").val(output); //call the callback callback(output); } else { alert('No results found'); } } else { alert('Geocoder failed due to: ' + status); } }); } 
Sign up to request clarification or add additional context in comments.

Comments

1

Change reversegeocode to take a callback parameter (also known as a continuation).

Encapsulate all the stuff that needs to wait for reversegeocode to finish, putting it into an in-place, nameless function.

(Note the similarity to what you're already doing for the click handler.)

With this approach you are also free to add parameters to the callback, which you can use to pass data directly through.

$('.addButton').click(function() { reversegeocode(function(some_data) { var location = $("#location").val();//the value I need //...stuff... }); }); function reversegeocode(callback){ //...stuff... geocoder.geocode({'latLng': latlng}, function(results, status) { if (status == google.maps.GeocoderStatus.OK) { //...stuff... } else { alert('Geocoder failed due to: ' + status); } callback(some_data); }); } 

Comments

0

You need to use a callback function in the reversegeocode function.

Comments

0

The same exact way as you do ajax :)

$('.addButton').click(function() { reversegeocode().done(function(location) { $.post("<?php echo $this->webroot;?>locations/add", {location:location}) .done(function (data) { $("#locationsHolder").html(data); }); }); }) 

To do this you will have reversegeocode return a jquery deferred promise

function reversegeocode() { return $.Deferred(function(d) { //do stuff and when it succeeds d.resolve(location); //or if it fails d.reject("something went wrong"); }).promise(); } 

2 Comments

Hi George - cool mustache by the way - I'm not sure I understand the return bit of this. I don't actually need it to return anything, is it not possible to do this without having to return anything?
@crazysarah You could, you certainly don't have to return anything (and then you wouldn't get a (location) parameter. However I recommend separating the component that does the reverse geocoding and the process of actually setting it in the UI. Return the location, and in one done handler set the #locationsHolder html and in another done handler do what I did above (read the deferred documentation if this is confusing to you). You shouldn't use html in the UI to communicate between functions - there's already a mechanism for that: parameters and return values.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.