var geocoder, map, point, fmtAdd, marker;
function mapLoad() {
geocoder = new google.maps.Geocoder();
var myOptions = {
zoom: 15,
mapTypeControl: false,
mapTypeId: google.maps.MapTypeId.ROADMAP
}
map = new google.maps.Map(document.getElementById("map"), myOptions);
address="W3 6BY";
if(address){geocoder.geocode({'address':address}, geocodeResult);}
else{alert("Postcode Incorrect");window.close();}
}
function geocodeResult(results, status) {
if (status == 'OK' && results.length > 0) {
point=results[0].geometry.location;
map.setCenter(point);
marker = new google.maps.Marker({map: map, position: point, draggable: true});
geocoder.geocode({latLng:point},function(results, status){
if(status == 'OK') {
if(results.length == 0) {
fmtAdd = 'None';
} else {
fmtAdd = results[0].formatted_address;
}
} else {
fmtAdd = 'Error';
}
alert(fmtAdd); // shows the address
});
alert(fmtAdd); // says undefined;
} else {
alert("Error: " + status);
}
}
mapLoad();
I want to show the formatted address from user's input who are in the UK. But I don't understand why the second alert is undefined? Didn't I defined the variable "fmtAdd" at the first line?
Your "second" alert is actually your first alert since it is executed first (geocode() is non blocking - it returns immediately).
At that point you "defined" fmtAdd, but you didn't initialize it.
var foo; alert(foo);
alerts undefined.
answering comment:
I thought it was a global variable, and once the geocode give
an value to it, I can retrieve that value even out of the geocode
function.
This is correct. The variable is initialized once the callback function passed to geocode() sets a value to it. And exactly that happens. After that "event" you can retrieve the value from your global variable also outside of your function.
The problem here is that you're trying to retrieve the value from fmtAddr before your callback function has completed (or is even called).
This is because geocode() is non-blocking. This means that it returns immediately, this is why you pass a callback function to geocode().
What happens
referring to this part of the code:
geocoder.geocode({ latLng: point }, function (results, status) {
if (status == 'OK') {
if (results.length == 0) {
fmtAdd = 'None';
} else {
fmtAdd = results[0].formatted_address;
}
} else {
fmtAdd = 'Error';
}
alert(fmtAdd); // shows the address
});
alert(fmtAdd); // says undefined;
In chronological order:
you call geocode(), passing a callback to it
geocode() starts an asynchronous request to the google servers and returns immediately
alert(fmtAdd); // says undefined;
the asynchronous request completes and calls your callback function
your callback function sets fmtAddr
what you need to do
execute your application in the correct order:
Create a function which does whatever you want to do with the formatted address.
Call this function from your callback. That is, after you set fmtAdd
(actually better would be to pass the formatted address directly to this function as a parameter, without using global variables)
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.
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]);
}
});
}
}
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!
I'm looking for a way to trigger user geolocation navigator function from another function mapInit(). It nearly works, but I can't have a proper callback of getCurrentPosition() to confirm it went well.. it return undefined each times.
My geolocation object will have to achieve other tasks so I don't want it to trigger mapInit(). It should have to get user location, record it and return trueor false.. Any guess?
Thanks :)
// Get user current position, return true or false
//
var geolocation = {
get: function() {
if (alert(navigator.geolocation.getCurrentPosition(this.success, this.error, {
enableHighAccuracy: true,
maximumAge: 5000
})) {
return true;
} else {
return false;
}
},
success: function(position) {
this.last = position; // record last position
return true;
},
error: function() {
alert('code: ' + error.code + 'n' + 'message: ' + error.message + 'n')
return false;
},
last: undefined,
}
// Initialize leaflet map and get user location if coords are undefined
//
var mapInit = function(latitude, longitude) {
if (!latitude && !longitude) { // if no latlng is specified, try to get user coords
if (geolocation.get()) {
latitude = geolocation.last.coords.latitude;
longitude = geolocation.last.coords.longitude;
} else {
alert('oups!');
}
}
var map = L.map('map').setView([latitude, longitude], 15);
L.tileLayer('http://{s}.tile.cloudmade.com/#APIKEY#/68183/256/{z}/{x}/{y}.png', {
minZoom: 13,
maxZoom: 16,
}).addTo(map);
var marker = L.marker([latitude, longitude]).addTo(map);
}
Not sure I understand what you're trying to do but when you call "getCurrentPosition" the first argument you pass is a method that will be called with the Position once it is retrieved. As you said in your comment getCurrentPosition will always return immediately but the callback method will be called if the user position can be retrieved (it may never be called):
navigator.geolocation.getCurrentPosition( function(position) {
var lat = position.coords.latitude;
var lon = position.coords.longitude;
//do something like recent the Map
});
You will need to create the Leaflet Map first with some default coordinates and then recenter the map with the coordinates provided to the callback method.
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.