I have a (hopefully quite simple) Javascript problem. I've search but found nothing that is really relevant to the problem.
Basically I have a function (addToGlobe) that calls two other functions (codeAddressLat and codeAddressLng) as it runs. The two called functions should both return a float value to the first function, which then uses them. The subfunctions definitely work correctly - I did a print statement to check that the "numfinal" variable in each has a value, and it does.
However, when I add print statements to the calling function (as commented in the code), it returns 'undefined'. Therefore, the problem seems to be when the numfinal value is returned.
Thanks :)
function addToGlobe(uname, uid, pmcity) {
// Get lat & long of city
var pmlat = codeAddressLat(pmcity);
var pmlong = codeAddressLng(pmcity);
log(pmlat); // PROBLEM! Prints 'undefined'
log(pmlong); // PROBLEM! Prints 'undefined'
// Rest of function removed to keep it simple
}
function codeAddressLat(inputcity) {
geocoder = new google.maps.Geocoder();
var latlng = new google.maps.LatLng(-34.397, 150.644);
geocoder.geocode( { 'address': inputcity}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
var llsplit = new Array();
bkresult = String(results[0].geometry.location);
bkresult = bkresult.replace(/[\(\)]/g, "");
llsplit = bkresult.split(',');
numfinal = parseFloat(llsplit[0]);
return numfinal;
} else {
log('<b><font color="#C40031">Geocode was not successful:</b> ' + status);
}
});
}
function codeAddressLng(inputcity) {
// Basically the same function as above. Removed for simplicity
}
codeAddressLat is not actually returning anything. The anonymous function it passes to geocoder.geocode is.
Since geocoder.geocode is running asynchronously, codeAddressLat can't wait around for its answer. So codeAddressLat really can't return anything of value. Instead codeAddressLat needs to become asynchronous too. This is a common pattern in JavaScript.
function addToGlobe(uname, uid, pmcity) {
codeAddressLat(pmcity, function(pmlat) {
// do something with pmlat
});
...
}
function codeAddressLat(inputcity, callback) {
geocoder = new google.maps.Geocoder();
var latlng = new google.maps.LatLng(-34.397, 150.644);
geocoder.geocode( { 'address': inputcity}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
var llsplit = new Array();
bkresult = String(results[0].geometry.location);
bkresult = bkresult.replace(/[\(\)]/g, "");
llsplit = bkresult.split(',');
numfinal = parseFloat(llsplit[0]);
// instead of returning, call the callback with the result
callback(numfinal);
} else {
log('<b><font color="#C40031">Geocode was not successful:</b> ' + status);
}
});
}
You don't have a return statement in codeAddressLat, you have one inside a callback function defined inside codeAddressLat.
Your function codeAddressLat is not actually returning a value but calling function that you pass a callback function which is returning a value. You need to wait until the geocode operation is complete to retrieve the value of numfinal.
Your function codeAddressLat is not returning any value at all hence you are getting undefined as output.
The geocode request in the codeAddressLat method call and will not return the value to the caller. Your return is of a different scope.
Does this work?
function codeAddressLat(inputcity) {
geocoder = new google.maps.Geocoder();
var latlng = new google.maps.LatLng(-34.397, 150.644);
return geocoder.geocode( { 'address': inputcity}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
var llsplit = new Array();
bkresult = String(results[0].geometry.location);
bkresult = bkresult.replace(/[\(\)]/g, "");
llsplit = bkresult.split(',');
numfinal = parseFloat(llsplit[0]);
return numfinal;
} else {
log('<b><font color="#C40031">Geocode was not successful:</b> ' + status);
}
});
}
That geocoder.geocode function looks like it is asynchronous. Your codeAddressLat and codeAddressLng functions returns void before the geocoder.geocode function has got data back from the server.
A way to get around it is to nest your calls to geocoder.geocode and use variable scoping so that when all the AJAX calls have returned you can call your addToGlobe function passing the two parameters you want.
Something like this:
codeAddressLatAndLong(pmcity);
function addToGlobe(pmlatlat, pmlatlong) {
log(pmlat); // PROBLEM! Prints 'undefined'
log(pmlong); // PROBLEM! Prints 'undefined'
// Rest of function removed to keep it simple
}
function codeAddressLatAndLong(inputcity) {
// stuff
geocoder.geocode( { 'address': inputcity}, function(results, status) {
// stuff goes here
pmlat = parseFloat(llsplit[0]);
geocoder.geocode({...}, function(results, status) {
// more stuff
pmlatlong = something;
addToGlobe(pmlatlat, pmlatlong);
});
});
}
Welcome to the world of AJAX.
Related
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 8 years ago.
So, I have this piece of code:
function centermap(){
var geocoder = new google.maps.Geocoder();
var address = document.getElementById('office_address').value;
var new_location = "";
geocoder.geocode( {'address': address}, function(results, status, new_location) {
if (status == google.maps.GeocoderStatus.OK) {
new_location = results[0].geometry.location;
console.log(new_location); // output is fine here
}
else {
console.log("Geocode was not successful for the following reason: " + status);
}
})
console.log(new_location); // output is "" - which is the init value
return new_location // the returned object is also ""
};
$("input[id=office_address]").change(function(){
var coordinates = new Array();
var location = centermap();
coordinates.push(location.geometry.location.lat());
coordinates.push(location.geometry.location.lng());
map.setView(coordinates, 14);
});
What am I not getting regarding the scopes here? How can I set the "outside" new_location to be the gecode result? Please feel free to point all the mistakes on my understanding on this
EDIT: I have read the answers on this and this so questions but I didn't manage to do what I want.
As somebody pointed out in the comments, the geocode function is asynchronous, so as soon as it is executed it will return without any value.
Consider this workflow:
...
geocoder.geocode( ... );
// this is executed straight after you call geocode
console.log(new_location);
...
...
// probably at a certain point here your geocode callback is executed
function(results, status, new_location) {
if (status == google.maps.GeocoderStatus.OK) {
...
});
The important thing is to pass a callback function to your centermap as well:
$("input[id=office_address]").change(function(){
var coordinates = new Array();
// pass a callback to execute when geocode get the results
centermap(function (location){
coordinates.push(location.geometry.location.lat());
coordinates.push(location.geometry.location.lng());
map.setView(coordinates, 14);
});
});
function centermap(callback){
var geocoder = new google.maps.Geocoder();
var address = document.getElementById('office_address').value;
geocoder.geocode( {'address': address}, function(results, status) {
var new_location = '';
if (status == google.maps.GeocoderStatus.OK) {
new_location = results[0].geometry.location;
console.log(new_location); // output is fine here
}
else {
console.log("Geocode was not successful for the following reason: " + status);
}
// at this point we return with the callback
callback(new_location);
});
// everything here is executed before geocode get its results...
// so unless you have to do this UNRELATED to geocode, don't write code here
};
I've been struggling with this for a few hours now, and even after reading several examples on Stack I've been unable to get this working. It doesn't help that I'm a JS newbie.
I'm trying to retrieve information about an address from the Google Geocoder API, and then pass the object over to another function. Per my reading I understand that function I'm using to retrieve the information is asynchronous, and therefore I need to use a callback function to read it. However, when I attempt to do this I still get 'undefined' returned by my console. I know that the information is coming from Google fine, since when I use console.log() on the result object it returns correctly.
Anyways, here's what I'm working with:
function onSuccess(position) {
getLocationData(position, function(locationData) {
console.log(locationData);
});
}
function getLocationData(position, callback) {
geocoder = new google.maps.Geocoder();
var location = 'Billings,MT';
if( geocoder ) {
geocoder.geocode({ 'address': location }, function (results, status) {
if( status == google.maps.GeocoderStatus.OK ) {
return results[0];
}
});
}
callback();
}
Like I mentioned though, all I get with this is 'undefined'. If I put 'console.log(results[0])' above the getLocationData() return, the object returned is correct though. Any help would be much appreciated.
Your problem is, that you didn't connect the callback to the return. As the geocode() function itself is already asynchronous, the return doesn't have any effect there. Instead you have to pass the values you are returning here directly to the callback-function. Like this:
function getLocationData(position, callback) {
geocoder = new google.maps.Geocoder();
var location = 'Billings,MT';
if( geocoder ) {
geocoder.geocode({ 'address': location }, function (results, status) {
if( status == google.maps.GeocoderStatus.OK ) {
callback(results[0]);
}
});
}
}
I am trying to find a set of latitude longitude values and assign it to a variable.
My code looks like this
var k = findLattitudeLongitude("Italy");
console.log(k) // comes undefined
function findLattitudeLongitude(input){
var geocoder = new google.maps.Geocoder();
geocoder.geocode( { 'address': input}, function(results, status) {
var location = results[0].geometry.location;
return location;
});
}
but it comes as undefined. What is the best way to achieve the above requirement. Is there any other method?
Actually what you've done is correct.
The problem is the response received from Google geocoder is taking some time.
I've created a fiddle for a better understanding.
it's strange that the function return undefined, what you can do is to call another function, this way work with me fine, you can pass latitude and longitude params like the code below or the whole object
$( document ).ready(function() {
function getlatlan(){
geocoder = new google.maps.Geocoder();
geocoder.geocode( { 'address': "Italy"}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
dosome(results[0].geometry.location.nb,results[0].geometry.location.mb)
return true;
;
}});
}
function dosome(lat,lng){
console.log(lat,lng);
}
getlatlan();
});
This question already has answers here:
How do I return a variable from Google Maps JavaScript geocoder callback?
(5 answers)
Closed 9 years ago.
I just can't find what's wrong with this bit of code:
function getLocationName(latitude, longitude) {
if (isNaN(parseFloat(latitude)) || isNaN(parseFloat(longitude))) {
return false;
}
var locationName;
var geocoder = new google.maps.Geocoder();
var latlng = new google.maps.LatLng(latitude, longitude)
// Reverse Geocoding using google maps api.
geocoder.geocode({ 'latLng': latlng }, function (results, status) {
if (status == google.maps.GeocoderStatus.OK) {
if (results[1]) {
locationName = results[1].formatted_address;
alert(locationName);
}
else {
locationName = "Unknown";
}
}
else {
locationName = "Couldn't find location. Error code: " + status;
}
});
alert(locationName);
return locationName;
}
I call this from a jquery event handler like this:
$("#id").on("event", function (event, ui) {
$("#userLocation").text(getLocationName(latitude, longitude));
});
Weird part is that the first alert gets the correct value of 'locationName' but the second one always returns 'undefined'. I tried initializing the variable with a value and in that case the first alert again returned the correct location name but the second one returned the initialization value. This gives me a notion that this might be a variable scope related problem but I just can't figure what.
PS. I don't have any other variables (local/global) by the same name.
Update: The alert works fine now (thanks to Lwyrn's answer) but the return value is still wrong. I've followed the answers in the linked SO question and still I couldn't 'return' the right value. The alert did work fine.
You have to move "alert(locationName);" into the geocoder.geocode callback. Because geocoder.geocode executes an AJAX request. When you throw the alert the var locationName is still undefined (not set).
Try it like this
function getLocationName(latitude, longitude, callback) {
if (isNaN(parseFloat(latitude)) || isNaN(parseFloat(longitude))) {
return false;
}
var locationName;
var geocoder = new google.maps.Geocoder();
var latlng = new google.maps.LatLng(latitude, longitude)
// Reverse Geocoding using google maps api.
geocoder.geocode({ 'latLng': latlng }, function (results, status) {
if (status == google.maps.GeocoderStatus.OK) {
if (results[1]) {
locationName = results[1].formatted_address;
alert(locationName);
}
else {
locationName = "Unknown";
}
}
else {
locationName = "Couldn't find location. Error code: " + status;
}
alert(locationName);
callback(locationName);
});
}
To get the "return" you have to create a your own callback.
Try like this
$("#id").on("event", function (event, ui) {
getLocationName(latitude, longitude, function(result){
$("#userLocation").text(result);
});
});
As for the alert, the return is called before the ajax request. So you have to use a callback to be called when the ajax request has done his job!
This question already has answers here:
Accessing array from outside of geocode loop
(2 answers)
How do I return the response from an asynchronous call?
(41 answers)
Closed 10 years ago.
I'm trying to create a function that utilizes Google Javascript V3's geocoding capabilities and returns an array with the longitude and latitude. For some reason the return array is not being populated using the function. Thanks for your help!
Code:
function getCoords(address) {
var latLng = [];
var geocoder = new google.maps.Geocoder();
geocoder.geocode( { 'address': address}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
latLng.push(results[0].geometry.location.lat());
latLng.push(results[0].geometry.location.lng());
return latLng;
} else {
alert("Geocode was not successful for the following reason: " + status);
}
});
}
var test_arr;
test_arr = getLatLng('New York');
alert(test_arr[0] + ',' + test_arr[1]) // I'm getting a test_arr is undefined here.
Read up on using callback functions in Javascript. This article might be helpful.
As Jon pointed out, you can solve this by passing a callback function into your getCoords method. It's a way of waiting for the response to come back from Google. You define a function that will be called when the geocoding is done. Instead of returning the data, you'll call the provided function with the data as an argument.
Something like this:
function getCoords(address, callback) {
var latLng = [];
var geocoder = new google.maps.Geocoder();
geocoder.geocode( { 'address': address}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
latLng.push(results[0].geometry.location.lat());
latLng.push(results[0].geometry.location.lng());
callback(latLng);
} else {
alert("Geocode was not successful for the following reason: " + status);
}
});
}
getCoords('New York', function(latLng) {
var test_arr;
test_arr = latLng;
alert(test_arr[0] + ',' + test_arr[1])
// Continue the rest of your program's execution in here
});
#Matt Ball should have posted the answer. :)
The reason test_arr is undefined is because you're evaluating it immediately before the results come back.
If you did a setTimeout (which you shouldn't do), you would notice eventually the array will have something in it.
setTimeout(function(){
alert(test_arr) // has stuff...
}, 5000);
Instead, you can pass an anonymous function to getCoords as a callback. This function gets executed once the coordinates are available.
function getCoords(address, callback) {
...
var lng = results[0].geometry.location.lng();
var lat = results[0].geometry.location.lat();
callback([lat, lng]);
...
}
getCoords("New York", function(coords) {
alert(coords); // works
});