Hi I have some trouble with an array with a for in JavaScript. Let's have a look:
var Villes = [
['Versailles+France', 'upr2.png'],
['Paris+France', 'upr5.png'],
['Bruxelle+Belgique', 'upr4.png'],
['Manchester+Angleterre', 'upr1.png'],
['Monaco+Monaco', 'upr3.png']
];
function initialize() {
var mapOptions = {
zoom: 5,
center: new google.maps.LatLng(46.225453,2.219238),
mapTypeId: google.maps.MapTypeId.ROADMAP
};
var map = new google.maps.Map(document.getElementById("map-canvas"), mapOptions);
var geocoder = new google.maps.Geocoder();
for (var i = 0; i < Villes.length; i++) {
var ville = Villes[i];
geocoder.geocode( { 'address': ville[0]}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
var marker = new google.maps.Marker({position: results[0].geometry.location,map: map,icon: ville[1]});
alert(ville[1] + status);
} else {
alert("Geocode n'a pas fonctionner. Erreur: " + status);
}
});
}
}
My Map comes with all my marker but the icon never change like ville[1] is a static call to upr3.png I'm not used to JS and it's the first time I see that.
By the time the callback you give to geocode is called, i has the value of end of loop.
The usual generic solution is to protect it by an immediately called function expression :
for (var i = 0; i < Villes.length; i++) {
(function(ville){
geocoder.geocode( { 'address': ville[0]}, function(results, status)
...
});
})(Villes[i]);
}
As the scope of a variable is the function in which it is declared, this makes the new variable ville immune to the variation of the loop.
The geocode call is asynchronous, which means that you will loop through all the places and send requests, then the responses will arrive. At that time you have already run through the loop, and the ville variable has the value of the last place.
Put a function expression around the code in the loop, so that each iteration has its own copy of the variable:
for (var i = 0; i < Villes.length; i++) {
(function(ville){
geocoder.geocode( { 'address': ville[0]}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
var marker = new google.maps.Marker({position: results[0].geometry.location,map: map,icon: ville[1]});
alert(ville[1] + status);
} else {
alert("Geocode n'a pas fonctionner. Erreur: " + status);
}
});
})(Villes[i]);
}
The problem is that ville is not an array, so by the time the for loop finishes, ville only has the value of the last item in your initial array (png3). You need call the function right after setting the value to ville
Related
Using Google Maps and the Geocoder, I'm trying to loop over an object of addresses, return LatLng addresses for them, and create markers using both the original details and the latlng address in the setMarker function below.
The problem is, the response[a] is being overwritten by the last address in the object, because the for loop is running ahead of the AJAX results being returned.
How can I save the data in the current response[a] being looped over, so that when setMarker() is later called, it contains the right information?
Thanks
var limit = 0;
for (a in response){
if(limit<5){ // limit API calls
var addr = [response[a].Addr1, response[a].City, response[a].Zip];
geo = new google.maps.Geocoder();
geo.geocode({
address: addr.join(", "),
componentRestrictions: {
// country: 'UK'
}
}, function (results, status) {
if (status == google.maps.GeocoderStatus.OK && results) {
var latitude = results[0].geometry.location.lat();
var longitude = results[0].geometry.location.lng();
var latlng = new google.maps.LatLng(latitude, longitude);
if(latitude!="" && longitude!=""){
bounds.extend(latlng);
map.fitBounds(bounds);
_this.setMarker(map, limit, latlng, response[a]);
}
} // if geo results
});
}
limit++;
}
The problem you are facing is a classic one that can be solved using closure function.
Current code looks something like :
var a[20];
for(i=0;i<20;i++) {
some_async_method() {
//code that uses 'a[i]'
}
}
Using closure to preserve the scope of var a inside a async function :
var a[20];
for(i=0;i<20;i++) {
(function(_a){
some_async_method() {
//code that uses 'a[i]' as '_a'
}
})(a[i]);// self calling function that preserves the scope of a[i]
}
So your code will look like :
var limit = 0;
for (a in response){
if(limit<5){ // limit API calls
var addr = [response[a].Addr1, response[a].City, response[a].Zip];
geo = new google.maps.Geocoder();
(function(response_a){ // closure function to preserve scope of 'response[a]'
geo.geocode({
address: addr.join(", "),
componentRestrictions: {
// country: 'UK'
}
}, function (results, status) {
if (status == google.maps.GeocoderStatus.OK && results) {
var latitude = results[0].geometry.location.lat();
var longitude = results[0].geometry.location.lng();
var latlng = new google.maps.LatLng(latitude, longitude);
if(latitude!="" && longitude!=""){
bounds.extend(latlng);
map.fitBounds(bounds);
_this.setMarker(map, limit, latlng, response_a);
}
} // if geo results
});
})(response[a]);
}
limit++;
}
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 4 years ago.
I am trying to add multiple markers to google map.
My code :
function createMarkers(myArray) {
var myOptions = {
zoom:6,
center: new google.maps.LatLng(28.704059, 77.102490)
};
var map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
//shows the object in console with length of 3
console.log(myArray);
//but here length return is 0 so no Entry on FOR Loop
console.log(myArray.length);
for(var x=0;x<myArray.length;x++){
var marker = new google.maps.Marker({
position: myArray[i],
map: map,
title: 'Hello World!'
});
}
}
function initialize(){
var geocoder = new google.maps.Geocoder();
var cityArray = ['Agra','Delhi','Varanasi'];
var myLatLng = [];
for(var i=0;i<cityArray.length;i++){
geocoder.geocode({
'address': cityArray[i]+', India'
}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
var Lat = results[0].geometry.location.lat();
var Lng = results[0].geometry.location.lng();
myLatLng.push({'lat': Lat, 'lng': Lng});
} else {
alert("Something got wrong " + status);
}
});
}
//console.log(myLatLng);
createMarkers(myLatLng);
}
google.maps.event.addDomListener(window, "load", initialize);
<style>
html,
body,
#map_canvas {
height: 100%;
width: 100%;
margin: 0px;
padding: 0px
}
</style>
<div id="map_canvas"></div>
I got latitute and logitude in array of objects. Now i want to iterate over this in the createMarkers(myLatLng) function. But in this function i am able to log this object to console and showing length of 3 . But when want to get its length for looping it always return 0;
As stated in the comments, your problem is with async callback.
when JS preforms "async" actions (like jQuery ajax and geocoder.geocode) the action takes some time but the code below this request is executed without waiting.
that's why geocoder.geocode has that function inside it that checks if it was successful, this one:
function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
var Lat = results[0].geometry.location.lat();
var Lng = results[0].geometry.location.lng();
myLatLng.push({'lat': Lat, 'lng': Lng});
createMarkers(myLatLng); // THIS IS A NEW LINE
} else {
alert("Something got wrong " + status);
}
that only executes after your call was completed.
just pass createMarkers(myLatLng); inside that callback function and it should work as planned.
I'm looping through about 60 addresses to get them geocoded for use on a Google Map. My callback (below) seems to work well for collecting the locations, but I need to know how to relate them to the address objects I'm looping through. I can't find anything in the geocode response that tells me which of my requests it 'came from.'
Is there a way to do that?
This is my function:
geocode() {
var lv_location;
var geocoder = new google.maps.Geocoder();
if (geocoder) {
geocoder.geocode({'address' : this.address},
function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
// what data in results can be used to relate the location to the address?
lv_location = results[0].geometry.location;
}
markerCounter++;
if (markerCounter >= 60) finishSurnames();
});
}
In JavaScript you can use Immediately-invoked function expression that will create a function scope also known as closure. You should change your function to something similar to
geocode() {
var lv_location;
var geocoder = new google.maps.Geocoder();
if (geocoder) {
geocoder.geocode({'address' : this.address}, (function(originalAddress){
return function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
// what data in results can be used to relate the location to the address?
//You can use the originalAddress variable here to relate result to request
lv_location = results[0].geometry.location;
}
markerCounter++;
if (markerCounter >= 60) finishSurnames();
};
})(this.address));
}
}
Have a look at my example, it geocodes 3 addresses and print in console result and corresponding request string
var addresses = [
'av Diagonal 197, Barcelona',
'av Lucas Vega 53, San Cristobal de La Laguna',
'Metrologichna 14, Kiev'
];
function initMap() {
var map = new google.maps.Map(document.getElementById('map'), {
zoom: 8,
center: {lat: -34.397, lng: 150.644}
});
var geocoder = new google.maps.Geocoder();
addresses.forEach( function(address) {
geocode(geocoder, address);
});
}
function geocode(geocoder, address) {
geocoder.geocode({'address': address}, (function(originalAddress) {
return function(results, status) {
if (status === 'OK') {
console.log("Search: " + originalAddress + "->" + results[0].geometry.location.toString());
} else {
console.log("Search: " + originalAddress + "->" + status);
}
};
})(address));
}
#map {
height: 100%;
}
html, body {
height: 100%;
margin: 0;
padding: 0;
}
<div id="map"></div>
<script async defer
src="https://maps.googleapis.com/maps/api/js?v=3&key=AIzaSyDztlrk_3CnzGHo7CFvLFqE_2bUKEq1JEU&callback=initMap">
</script>
I hope this helps!
I have two set of lat and lng.
I want both address and stored in some variable:
var geocoder = new google.maps.Geocoder();
for(var i=0; i<json_devices.length; i++)
{
var lat = json_devices[i].latitude;
var lng = json_devices[i].longitude;
console.log(lat);
console.log(lng);
var latlng = new google.maps.LatLng(lat,lng);
geocoder.geocode({'latLng': latlng}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
if (results[1]) {
address=results[1].formatted_address;
} else {
alert('No results found');
}
} else {
alert('Geocoder failed due to: ' + status);
}
});
console.log(address);
}
In this, lat & lan get correctly. But address are not stored in variable. What is the mistake?
I am using this method and it is working perfect for me.
Please have a look on it.
public String getAddressFromLatLong(GeoPoint point) {
String address = "Address Not Found";
Geocoder geoCoder = new Geocoder(
getBaseContext(), Locale.getDefault());
try {
List<Address> addresses = geoCoder.getFromLocation(
point.getLatitudeE6() / 1E6,
point.getLongitudeE6() / 1E6, 1);
if (addresses.size() > 0) {
address =addresses.get(0).getAddressLine(0);
if(address.length()<=0)
address =addresses.get(0).getSubLocality();
}
}
catch (Exception e) {
e.printStackTrace();
}
return address;
}
Here the Google geocode is asynchonous type of function call.
From DOCS:
Accessing the Geocoding service is asynchronous, since the Google Maps
API needs to make a call to an external server. For that reason, you
need to pass a callback method to execute upon completion of the
request. This callback method processes the result(s). Note that the
geocoder may return more than one result.
So you can't get the address like that, instead use the common approach called callback.
Here I have created a sample code to explain the process, which can be altered by yourself.
var geocoder;
function codeLatLng(callback) {
geocoder = new google.maps.Geocoder();
var input = document.getElementById("latlng").value;
var latlngStr = input.split(",", 2);
var lat = parseFloat(latlngStr[0]);
var lng = parseFloat(latlngStr[1]);
var latlng = new google.maps.LatLng(lat, lng);
geocoder.geocode({
'latLng': latlng
}, function (results, status) {
if (status == google.maps.GeocoderStatus.OK) {
if (results[1]) {
address = results[1].formatted_address;
callback(address);
} else {
alert("No results found");
}
} else {
alert("Geocoder failed due to: " + status);
}
});
}
$('input[type="button"]').on('click', function () {
codeLatLng(function (address) { //function call with a callback
console.log(address); // THE ADDRESS WILL BE OBTAINED
})
});
JSFIDDLE
I'm sure this is really simple but I haven't had much luck figuring out what's wrong. I'm creating an empty array (locations), filling it with location objects in the getPartnerLocations function and then trying to plot the locations on the map with the drop function. The problem I'm having is that inside the drop function the locations array which has stuff in it is returning a length of zero so the loop in the isn't working. Any tips or ideas about what's going on here would be greatly appreciated.
var markers = [];
var locations = [];
var iterator = 0;
var map;
var geocoder;
var newYork = new google.maps.LatLng(40.7143528, -74.0059731);
function initialize() {
var mapOptions = {
zoom: 12,
mapTypeId: google.maps.MapTypeId.ROADMAP,
center: newYork
};
map = new google.maps.Map(document.getElementById("map_canvas"),mapOptions);
}
function getPartnerLocations() {
geocoder = new google.maps.Geocoder();
$('.partner').each(function(index){
var street = $('.partner-streetaddress',this).text();
var city = $('.partner-city',this).text();
var state = $('.partner-state',this).text();
var country = $('.partner-country',this).text();
var address = street + ', ' + city + ', ' + state + ', ' + country;
geocoder.geocode( { 'address': address}, function(results, status)
{
if (status == google.maps.GeocoderStatus.OK)
{
locations.push( results[0].geometry.location );
console.log(locations[index]);
}
else
{
console.log('failed to geocode address: ' + address);
}
});
});
initialize();
drop();
}
function addMarker() {
console.log('add marker function');
markers.push(new google.maps.Marker({
position: locations[iterator],
map: map,
draggable: false,
animation: google.maps.Animation.DROP
}));
iterator++;
}
function drop()
{
console.log(locations.length);
for (var i = 0; i < locations.length; i++) {
setTimeout(function() {
addMarker();
}, i * 200);
}
}
getPartnerLocations();
geocode is an asynchronous function.
The callback doesn't execute until some time after you call drop.
Therefore, when you call drop, the array is still empty.
You need to call initialize and drop after the last AJAX call replies, in the geocode callback.