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!
Related
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Google map sync geocode delay
(2 answers)
Closed 4 years ago.
I am trying to get address info for my project. I can see the address by alert() method if i write it inside the geocode function. but if i outside of the function, it returns undefined.
tried to write the variable name like window.adres but didnt work. i think because of an another function with is parent of this.
how to make that variable global and change the value?
var geocoder = new google.maps.Geocoder;
var adres;
var latlng = {lat: parseFloat(lat), lng: parseFloat(lon)};
geocoder.geocode({'location': latlng}, function(results, status) {
if (status === 'OK') {
if (results[0]) {
adres = results[0].formatted_address;
//window.adres = ... is not working. i think because of an another function which is parent of these lines.
alert(adres); //returns address
}
} else {
window.alert('Geocoder failed due to: ' + status);
}
alert(adres); //returns undefined
also i tried that
var geocoder = new google.maps.Geocoder;
var latlng = {lat: parseFloat(lat), lng: parseFloat(lon)};
var adres = geocoder.geocode({'location': latlng}, function(results, status) {
if (status === 'OK') {
if (results[0]) {
return results[0].formatted_address;
}
} else {
window.alert('Geocoder failed due to: ' + status);
}
alert(adres); //returns undefined too
If you set a global variable with window dot whatever, you will be able to get to it later by calling the same (fully qualified) variable.
Here is an example that proves this (run the snippet to see it in action).
function setVarInFunction(){
window.adres = 'here is some text';
}
console.log(window.adres); // should be undefined
setVarInFunction();
console.log(window.adres); // now there should be something
The reason alert(adres) is not working the way you expect is that:
you create a variable at the beginning
you execute an asynchronous request off to Google to do some work, and update your variable when it comes back from Google
you execute your alert to show the var value, but you have no guarantee that Google has actually responded yet with it's data (it almost certainly has not yet responded)
What do you want to do with that value? You almost certainly don't want to just alert() it, right? Whatever you want to do with it, you should do in the block where it comes back from Google with success or failure.
You are missing the ending of your anonymous function.
This is an issue related to the callbacks in javascript.
Geocoder takes time to process your request. Thus, you alert address while it is not yet defined.
I have updated your code to new coding standards and added comments :
let geocoder = new google.maps.Geocoder;
let latlng = { lat: parseFloat(lat), lng: parseFloat(lon) };
let address = null;
// 1. The geocoder starts the process to find the address
geocoder.geocode({'location': latlng}, (results, status) => {
// 3. The geocoder finally located the address, because it takes time.
if (status === 'OK') {
if (results[0]) {
// This updated the variable with the correct result.
address = results[0].formatted_address;
// You should call here a new function, in order to do the rest of your work
}
} else {
window.alert('Geocoder failed due to: ' + status);
}
});
// 2. you output address
alert(address); // This won't work as address is set by the geocoder which is asynchronous
Hope this helps.
This question already has answers here:
Why is my variable unaltered after I modify it inside of a function? - Asynchronous code reference
(7 answers)
Closed 8 years ago.
I am trying to get a location name according to a lat-long coordinate from the Google maps geocoder. I cannot seem to extract the value from the geocoder callback. Here is my code:
geocoder = new google.maps.Geocoder();
var address = "";
var lat = 54.1234;
var lng = -114.1234;
var latlng = new google.maps.LatLng(lat, lng);
geocoder.geocode({'latLng': latlng } , function(results,status) {
if (status == google.maps.GeocoderStatus.OK) {
address = results[1].formatted_address; //want to get this address
} else {
address = 'error';
}
});
window.alert(address)
//address is an empty string here, but I want the value from inside the geocoder
//want access to address here to do other operations with it
The documentation for geocoder on the Google Developers site is almost non existant,
and I am having problems trying to find an example that is similar. I am out of my comfort area here, so any help
would be great!
The call is asynchronous, so the value exists inside the callback function:
geocoder.geocode({'latLng': latlng } , function(results,status) {
if (status == google.maps.GeocoderStatus.OK) {
address = results[1].formatted_address; //want to get this address
} else {
address = 'error';
}
window.alert(address);
});
// The code here runs before the callback function
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
};
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
});
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.