Google Map infowindow showing last value of loop - javascript

I have used for loop to display the markers and info window. But the infowindow showing only the last value of the loop.
Here is the code im using.
function initialize()
{
try
{
var geocoder;
var map;
geocoder = new google.maps.Geocoder();
var latlng = new google.maps.LatLng(41.511770, -72.809520);
var mapOptions = {
center: latlng,
zoom: 9,
disableDefaultUI: true,
mapTypeId: google.maps.MapTypeId.ROADMAP
}
map = new google.maps.Map(document.getElementById('map_canvas'), mapOptions);
var markers = JSON.parse('[{"address":"40C Leslie Road,Bridgeport,CT","Description":"Bridgeport - 82 Unit Community"},{"address":"56 Ironwood Road,West Hartford,CT","Description":"West Hartford - 45 Unit Community"}]');
var infoWindow = new google.maps.InfoWindow();
// var address;
for (i = 0; i < markers.length; i++)
{
var address = markers[i];
geocoder.geocode({ 'address': address.address }, function (results, status)
{
if (status == google.maps.GeocoderStatus.OK)
{
//map.setCenter(results[0].geometry.location);
var marker = new google.maps.Marker({
map: map,
icon:'Images/pin.png',
position: results[0].geometry.location
});
google.maps.event.addListener(marker, "click", function (e)
{
infoWindow.setContent("<div style='border:0px solid red;height:auto;;width:auto;'>" + address.Description + "</div>");
infoWindow.open(map, marker);
});
}
else {
//alert("Geocode was not successful for the following reason: " + status);
}
});
// map.setCenter(new google.maps.LatLng(41.511770, -72.809520))
}
}
catch (ex)
{
alert(ex.message);
}
}
google.maps.event.addDomListener(window, "load", initialize);
Please help me.
Thanks,
Venkat.

The problem is that geocoder.geocode is an asynchronous function. In other words, your execution moves away from the for loop before your requests has finished retrieving the values. Thus, you will be getting same address values, because it is the last value of the for loop when it had finished and you are placing everything to the same var address = ... variable.
To fix this, you need to wrap your geocoder.geocode request inside a self-executing anonymous function. As a result, your code works properly, because var address = ... is defined in it's own scope, together with the requests. See example below:
...
// Start of self-executing anonymous function
(function() {
var address = markers[i];
...
and:
...
// End of self-executing anonymous function
})();
// map.setCenter(new google.maps.LatLng(41.511770, -72.809520))
...
JS FIDDLE EXAMPLE (Remember to activate your icon image, I disabled it in that code.)
For further reading, I recommend self executing anonymous functions.
Cheers.

Related

Wait for elevation service request callback

I'm trying to build a little app with the Google Map API, and since it's my first javascript app (I already know about the language, but I almost never use it), I'm struggling with a little problem.
I'm trying to get the elevation related to a marker, using the ElevationService, in order to push the two datas ({marker, elevation}) into an array. However, the line where I push the datas into the array is hit before the callback function for getElevationForLocations has been called, resulting in the push of an undefined data (elevation).
I think I should use an asynchronous function in order to wait for the callback to be executed before the data has been pushed, but I don't know how to use it.
Could anyone give me indications on that ?
Thanks a lot,
Méta
P.S.: Here is my script
var markers = [];
function initMap()
{
var map = new google.maps.Map(document.getElementById('map'), {
zoom: 4,
center: {lat: -25.363882, lng: 131.044922 },
mapTypeId: 'terrain'
});
var elevator = new google.maps.ElevationService;
map.addListener('click', function(e) {
addMarker(e.latLng, map, elevator);
});
}
function getElevation(location, elevator) {
var elevation;
// Initiate the location request
elevator.getElevationForLocations({
'locations': [location]
}, function(results, status)
{
if (status === 'OK') {
// Retrieve the first result
if (results[0]) {
return results[0].elevation;
}
}
});
}
function placeMarkerAndPanTo(latLng, map) {
var marker = new google.maps.Marker({
position: latLng,
map: map
});
map.panTo(latLng);
return marker;
//markers.push(marker);
}
function addMarker(location, map, elevator)
{ var marker = placeMarkerAndPanTo(location, map);
var elevation = getElevation(location, elevator);
markers.push({marker, elevation});
}
Here is a simplified version of your code, using what I described in my comment.
var markers = [];
var elevator = new google.maps.ElevationService;
var map;
function initMap() {
map = new google.maps.Map(document.getElementById('map'), {
zoom: 4,
center: {
lat: -25.363882,
lng: 131.044922
},
mapTypeId: 'terrain'
});
map.addListener('click', function(e) {
addMarker(e.latLng);
});
}
function addMarker(location) {
elevator.getElevationForLocations({
'locations': [location]
}, function(results, status) {
if (status === 'OK') {
// Retrieve the first result
if (results[0]) {
var marker = new google.maps.Marker({
position: location,
map: map
});
map.panTo(location);
markers.push({
marker: marker,
elevation: results[0].elevation
});
console.log(markers);
}
}
});
}
google.maps.event.addDomListener(window, 'load', initMap);
#map {
height: 200px;
}
<script src="//maps.googleapis.com/maps/api/js"></script>
<div id="map"></div>
Edit: Seems there is a problem loading the API from the snippet at the moment (at least for me, it is crashing my browser), so here is a working JSFiddle as well.

Using the result of a geocoding API in a call to another API that needs user's location [duplicate]

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 5 years ago.
I am having some issues with my JavaScript in terms of properly returning a set of lat/long values from my function utilizing Google's geocoding API which takes an address and converts it into a lat,lang format which I can pass into Youtube's API to fetch a set of videos uploaded in that general vicinity.
The fix I settled upon is to create a hidden element which gets the lat long value, and then it is passed in. The following is the html tag that I settled on:
<div class="form-group" style="display:none;">
<label for="hidden">Extra:</label>
<input type="text" class="form-control" id="hidden" name="maxResults" placeholder="lat,lang">
</div>
However, my issue was that in my JavaScript, the way I originally had it, it would fail to return the value correctly. If I did an alert inside the function it would should the lat,lang values correctly. However, upon returning those values they are set as undefined for my location: Original code below:
function sendData() {
function initMap() {
var myLatLng = {lat: -25.363, lng: 131.044};
var map = new google.maps.Map(document.getElementById('map'), {
zoom: 4,
center: myLatLng
});
var marker = new google.maps.Marker({
position: myLatLng,
map: map,
title: 'Hello World!'
});
}
var geocoder = new google.maps.Geocoder();
// document.getElementById('submission').addEventListener('click', function() {
// geocodeAddress(geocoder, map);
// });
var myLatLng = {lat: -25.363, lng: 131.044};
var map = new google.maps.Map(document.getElementById('map'), {
zoom: 4,
center: myLatLng
});
var keyword = $('#q').val();
console.log(geocodeAddress(geocoder,map));
var location = geocodeAddress(geocoder,map);//$('#location').val();
var r = $('#locationRadius').val();
var maxResult = $('#maxResults').val();
console.log("keyword is: " + keyword);
$.get(
"../php/geolocation.php",
{
q: keyword,
location: location,
locationRadius: r,
maxResults: maxResult
},
function (data) {
$('#geolocation-results').html(data);
}
);
}
function buttonClick() {
$("#submission").submit(function(e) {
e.preventDefault();
});
sendData();
}
function geocodeAddress(geocoder, resultsMap) {
var address = document.getElementById('location').value;
geocoder.geocode({'address': address}, function(results, status) {
if (status === 'OK') {
//resultsMap.panTo(results[0].geometry.location);
var marker = new google.maps.Marker({
map: resultsMap,
position: results[0].geometry.location
});
var lat = results[0].geometry.location.lat();
var latS = toString(lat);
var lng = results[0].geometry.location.lng();
var lngS = toString(lng);
var latlngS = latS.concat(",",lngS);
var latlng = new google.maps.LatLng(lat, lng);
resultsMap.setCenter(latlng);
console.log(latlngS);
return latlngS;
} else {
alert('Geocode was not successful for the following reason: ' + status);
}
});
}
And below is the fix I settled upon
function geocode() {
var myLatLng = {lat: -25.363, lng: 131.044};
var map = new google.maps.Map(document.getElementById('map'), {
zoom: 4,
center: myLatLng
});
var geocoder = new google.maps.Geocoder();
geocodeAddress(geocoder, map);
}
function sendData() {
// document.getElementById('submission').addEventListener('click', function() {
// geocodeAddress(geocoder, map);
// });
var keyword = $("#q").val();
var r = $('#locationRadius').val();
var maxResult = $('#maxResults').val();
var location = $("#hidden").val();
console.log("keyword is: " + keyword);
$.get(
"../php/geolocation.php",
{
q: keyword,
location: location,
locationRadius: r,
maxResults: maxResult
},
function (data) {
$('#geolocation-results').html(data);
}
);
}
function buttonClick() {
$("#submission").submit(function(e) {
e.preventDefault();
});
sendData();
}
function geocodeAddress(geocoder, resultsMap) {
var address = document.getElementById('location').value;
geocoder.geocode({'address': address}, function (results, status) {
if (status === 'OK') {
resultsMap.setCenter(results[0].geometry.location);
var marker = new google.maps.Marker({
map: resultsMap,
position: results[0].geometry.location
});
var latS = results[0].geometry.location.lat().toString();
var lngS = results[0].geometry.location.lng().toString();
//alert((results[0].geometry.location.lat()));
var latLang = latS.concat(',', lngS);
$('#hidden').val(latLang);
console.log($('#hidden').val());
} else {
alert('Geocode was not successful for the following reason: ' + status);
}
});
}
The geocode function is called via an onblur in my html:
<div class="form-group">
<label for="location">location</label>
<input type="text" class="form-control" id="location" name="location" placeholder="Athens, GA" onblur="geocode()">
</div>
So really, to wrap up a rather lengthy code, I want to know how I can avoid having to maintain this disgusting fix in terms of having a hidden in-between form element? Apologies if this is a poorly worded question, I tried my best.
If you want sendData() to be called automatically with the location data as soon as the latLang in geocode's callback is available, then you could:
add a parameter to the function definition as in function sendData(location) and remove the var location = ... initialization and the hidden element because location will instead be set as a parameter to sendData;
and
call sendData(latlang) in geocode's anonymous function callback instead of setting the hidden value, on the line where you are currently setting hidden.
The idea is to create a function that can be called in the geocode callback
and consume its latlang data there instead of storing it globally.
Alternatively, you could set a global variable in a callback instead of the value of a hidden element, but then you can't use it until it is defined. That's no good for automatically chaining the steps, but might be ok if a human watches and pushes a button for the next step. Like the usage of hidden element values, it can lead to synchronization issues.

How do I prevent Google Maps from reinitializing after a geocode lookup?

I'm using the Google Maps Javascript API v.3. Below is the javascript that I've written. The goal is to initialize a map, and then do an address lookup via the Google maps geocoder, use that lat long to re-center the map, and set a marker down. I think I've got most of it working, except that after I recenter the map and place a marker, the page fires another onLoad event which causes the initialize() function to run again and resets all of my variables. After staring at this code for half a day, I'm not sure what is causing the extra onLoad event. What is causing it?
I am also new to writing javascript and working with Google maps, so I'm happy for other pointers on code quality. I know that I've tried to scope several variables globally and I'm not sure that I've done it correctly.
Here is the code (note: I plan on replacing the setTimeout function eventually, but I still haven't gotten the knack of programming asynch calls yet...I figured I will tackle that next).
<script type="text/javascript">
var map;
var geocoder;
var marker;
var latlng;
function initialize() {
geocoder = new google.maps.Geocoder();
var mapOptions = {
center: new google.maps.LatLng(47.606, -122.314),
zoom: 12
};
if (this.map == null){
this.map = new google.maps.Map(document.getElementById('map-canvas'), mapOptions);
}
}
function checkResponse(results, response){
if (response == google.maps.GeocoderStatus.OK) {
this.latlng = results[0].geometry.location;
this.map.setCenter(results[0].geometry.location);
this.marker = new google.maps.marker({ map: map, position: results[0].geometry.location});
}
else {
alert("Geocode was not successful for the following reason: " + response);
}
}
function searchAddress(){
var address = document.getElementById('address1').value;
var state = document.getElementById('state1').value;
var zip = document.getElementById('zip1').value;
var addressInput = address + ',' + state + ',' + zip;
geocoder.geocode( { 'address': addressInput}, function(results, status) {
//ToDo remove this setTimeout function and replace it with a callback
setTimeout(checkResponse(results, status), 3000);
});
}
google.maps.event.addDomListener(window, 'load', initialize);
</script>
When using a javascript function as the onsubmit function for a form, you must return false from the function if you don't want the page reloaded from the server.

Loading markers at intervals

In my project I have a google map, and I need to get markers on my map from database.
I have simple code like in example:
var geocoder;
var map;
function initialize() {
geocoder = new google.maps.Geocoder();
var latlng = new google.maps.LatLng(-34.397, 150.644);
var mapOptions = {
zoom: 8,
center: latlng
}
map = new google.maps.Map(document.getElementById('map-canvas'), mapOptions);
}
function codeAddress() {
var address = document.getElementById('address').value;
geocoder.geocode( { 'address': address}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
map.setCenter(results[0].geometry.location);
var marker = new google.maps.Marker({
map: map,
position: results[0].geometry.location
});
} else {
alert('Geocode was not successful for the following reason: ' + status);
}
});
google.maps.event.addListener(map, 'idle', function () {
getmarkers(map);
});
}
google.maps.event.addDomListener(window, 'load', initialize);
This code works well, but it has one lack - it loads new markers only if user moves map.
But I need to load markers also if user is just sitting in front of computer and look on a map, not moving it.
I think the best way to do this is to use setInterval(getmarkers(map), 3000) but if I use it except where that function google.maps.event.addListener(... it can't find map. Are there any ways to solve this problem?
there are 2 issues,
setInterval expects the first argument to be a function(but it isn't, it's a function-call which will be executed immediately). Use a anonymous function to execute the statement:
setInterval(function(){getmarkers(map);}, 3000);
place the setInterval-call at the end of initialize to be sure that map is defined.

Markers won't show on google maps

I need to place multiple markers on a google map. Here's the problem: I have an array of latitude/longitude data. I need to make a marker appear on the map for each lat/lng pair. But it won't. If I ask the function to print out the coordinates instead of marking them on the, map, it works fine. I don't get an error message either way, so I'm stuck. The page displays the map but without any markers. Here's the code of the function that should add markers:
//adds markers to the map
function addMarkers(locarray) {
var infowindow = new google.maps.InfoWindow();
var marker, i;
for (i = 0; i < locarray.length; i++) {
marker = new google.maps.Marker({
position: new google.maps.LatLng(locarray[i][0], locarray[i][1]),
map: map
});
google.maps.event.addListener(marker, 'click', (function(marker, i) {
return function() {
infowindow.setContent('some words');
infowindow.open(map, marker);
}
})(marker, i));
}
}
Here's the initialize function (called on body load):
function initialize() {
geocoder = new google.maps.Geocoder();
var latlng = codeAddress("<?php echo $_POST['postal']; ?>");
var myOptions = {
zoom: 11,
center: latlng,
mapTypeId: google.maps.MapTypeId.ROADMAP
}
map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
}
geocoder and map are declared as global variables. The codeAddress function returns lat and lng of the place I want to center the map around, it's been tested and works perfectly. It is NOT the problem, I'm leaving it out to simplify and keep PHP out of this.
And here is the script that declares the array and calls the addMarkers function:
<script type='text/javascript'>
var locations = [
[-33.890542, 151.274856],
[-33.923036, 151.259052],
[-34.028249, 151.157507]
];
addMarkers(locations)
</script>
Does anyone see anything wrong with this?

Categories