Reputation: 1156
What I am trying to do is on a submit click event, I want to geocode and address and set the values of a form and send those values via post.
In the following code, the alerts are to test the order in which the code is run.
I need the alert("2") and alert("3") to be processed before alert("4") so that there the variable result1 can have a value that will be used by the code after alert (4). As it stands now, the code fires in this order (the alerts pop up in this order): 1,4,2,3. There is an error on the line here:
var testvar = result1.lat();
The error is:
Uncaught TypeError: Cannot read property 'lat' of undefined
which makes sense since #4 is looking for the result1 variable before it can be set by the geocoder1 (point 2). It also does not populate the form fields.
$(document).ready(function() {
$("#myForm").submit(function() {
var address = $("#id_user_entered_address").val();
var geocoder = new google.maps.Geocoder();
var result;
alert("point 1");
geocoder.geocode({'address': address1},
function(results, status) {
if(status == google.maps.GeocoderStatus.OK){
result = results[0].geometry.location;
alert("point 2");
}
alert("point 3");
} );
alert("point 4");
var testvar = result.lat();
var testlong = result.lng();
$("#id_latitude").val(testvar);
$("#id_longitude").val(testlong);
alert("point 5");
});
});
That said, I can actually make this work properly (but it is a big hack since I do not want people needing to click on two buttons) when I do the following:
Create a separate function for the geocoding portion that is fired by a button click.
This leaves only the setting of the form variables in the submit function (on a the submit button of the form). I also have to change the result variable to global (by not using the var).
Then I click on the submit to fire the geocoding function, when that is complete, then I click on the submit button for the form, and all works as it should (i.e. post data is sent with the form). see following:
function firstgeocode() {
var address = $("#id_user_entered_address").val();
var geocoder = new google.maps.Geocoder();
geocoder.geocode({'address': address},
function(results, status) {
if(status == google.maps.GeocoderStatus.OK){
result = results[0].geometry.location;
alert("inside the geocode: " + result);
}
});
};
$(document).ready(function() {
$("#myForm").submit(function() {
var latres = result.lat();
var lonres = result.lng();
$("#id_latitude").val(latres);
$("#id_longitude").val(lonres);
})
});
I am not sure what the exact problem is as the problem and solution seems to be a mixture of: async vs sync in JS, callbacks, closures and scoping of variables in JS.
I have tried setting up a callback. The below script actually geocodes properly, changes the form fields on the screen, I can even use and alert to print the form element values, but the post data is not sent with the form, only the default values for the form are sent in the post:
$(document).ready(function() {
$("#myForm").submit(function() {
function geothis(callback){
var address = $("#id_user_entered_address").val();
var geocoder = new google.maps.Geocoder();
alert("point1");
geocoder.geocode({'address': address},
function(results, status) {
if(status == google.maps.GeocoderStatus.OK){
var result = results[0].geometry.location;
alert("inside the geocode: " + result);
callback(result);
}
});
};
function setform(result){
var latres = result.lat();
var lonres = result.lng();
$("#id_latitude").val(latres);
$("#id_longitude").val(lonres);
alert($("#id_longitude").val());
alert("point2");
};
geothis(setform);
});
});
Any ideas would be greatly appreciated.
Upvotes: 0
Views: 78
Reputation: 4342
I see you're using jQuery here so i would suggest to use the deferred object.
wrap your in the function getGeoLocation, which return a promise object, then at the point of alert('point3')
, resolve the deferred. For a quick code snippet, it would be
function getGeoLocation () {
var deferred = new $.Deferred();
geocoder.geocode({'address': address1},
function(results, status) {
if(status == google.maps.GeocoderStatus.OK){
result = results[0].geometry.location;
alert("point 2");
deferred.resolve();
}
alert("point 3");
});
return deferred.promise();
}
then after the line alert('point4')
, you could call the function like below, and the .done
will be called when you resolve
the deferred:
getGeoLocation().done(function() {
var testvar = result.lat();
var testlong = result.lng();
$("#id_latitude").val(testvar);
$("#id_longitude").val(testlong);
alert("point 5");
})
Upvotes: 1
Reputation: 207547
Welcome to the Asynchronous programming. You were on the right track using the callback, but your code can not submit until the call is complete. So you would need to cancel the form submission and when the Ajax code returns submit it after setting the values.
$("#myForm").submit(function(event) {
event.preventDefault(); //stop the form submission
and inside the callback
function setform(result){
var latres = result.lat();
var lonres = result.lng();
$("#id_latitude").val(latres);
$("#id_longitude").val(lonres);
//$("#myForm").off("submit"); //might need to remove the listener
$("#myForm")[0].submit(); //resubmit the form
};
Upvotes: 1