Google Maps / Wikipedia AJAX Call For Loop Issue - javascript

I am trying to generate Google Map markers with Wikipedia AJAX data in the infowindow using a for loop. I think there is a timing issue occurring, but after several weeks I cannot figure out how to resolve it. When I hardcode an identifier into the for loop to replace i (2 for example), the code works just fine...but when I use i, I get errors saying 'cannot read property [whatever] of undefined. I've played around with setTimeout and callbacks, but I can't seem to figure it out.
Here is my code:
var map;
var marker;
var infowindow;
var wikiURL;
var i;
var text;
var venueInfo;
var markers = [];
var markerNames = [];
var wikiURLs = [];
var venueArray = [];
//The Model - Pro/Collegiate Stadiums in PGH, Pa.
var venues = [
{
name: "PNC Park",
lat: 40.446855,
lng: -80.0056666
},
{
name: "Heinz Field",
lat: 40.4466765,
lng: -80.01576
},
{
name: "PPG Paints Arena",
lat: 40.439593,
lng: -79.989338
},
{
name: "Highmark Stadium",
lat: 40.4362358,
lng: -80.00959209999999
},
{
name: "Peterson Events Center",
lat: 40.443828,
lng: -79.962283
}
];
//marker creator
function createMarker(){
for (i=0; i <= venues.length; i++){
wikiURL = 'http://en.wikipedia.org/w/api.php?action=opensearch&search=' +venues[i].name+ '&format=json&callback=wikiCallback';
wikiURLs.push(wikiURL);
$.ajax ({
url: wikiURL,
dataType: "jsonp",
success: function(data){
text = data[2];
venueInfo = text[0];
console.log(venueInfo);
marker = new google.maps.Marker({
position: {lat: venues[i].lat, lng: venues[i].lng},
map: map,
draggable: false,
content: '<h2>'+venues[i].name+'</h2><p>'+venueInfo+'</p>'
});
markerNames.push(venues[i].name);
markers.push(marker);
infowindow = new google.maps.InfoWindow({
content: this.content
});
marker.addListener('click', function(){
infowindow.setContent(this.content);
infowindow.open(map, this);
});
}
});
}
}
//Map Initializer
function initMap() {
map = new google.maps.Map(document.getElementById('map'), {
center: {lat: 40.446855, lng: -80.0056666},
zoom: 14,
mapTypeId: 'satellite'
});
//viewmodel();
createMarker();
}
<!DOCTYPE html>
<html>
<head>
<link rel='stylesheet' href='css/bootstrap-theme.min.css'>
<link rel='stylesheet' href='css/main.css'>
</head>
<body>
<nav>
</nav>
<container>
<div id='map'>
</div>
</container>
<script type='text/javascript' src='js/jquery-3.2.1.min.js'></script>
<script type='text/javascript' src='js/knockout-3.4.2.js'></script>
<script type='text/javascript' async defer src="https://maps.googleapis.com/maps/api/js?key=AIzaSyA_WObUiYD7YpoYufR84re1LZHAJeAGXkY&v=3&callback=initMap">
</script>
<script type='text/javascript' src='js/app.js'></script>
</body>

As #jeff carey said, fix your loop and move your ajax code to separate function
function doAjax(i){
wikiURL = 'http://en.wikipedia.org/w/api.php?action=opensearch&search=' +venues[i].name+ '&format=json&callback=wikiCallback';
wikiURLs.push(wikiURL);
$.ajax ({
url: wikiURL,
dataType: "jsonp",
success: function(data){
text = data[2];
venueInfo = text[0];
marker = new google.maps.Marker({
position: {lat: venues[i].lat, lng: venues[i].lng},
map: map,
draggable: false,
content: '<h2>'+venues[i].name+'</h2><p>'+venueInfo+'</p>'
});
markerNames.push(venues[i].name);
markers.push(marker);
infowindow = new google.maps.InfoWindow({
content: this.content
});
marker.addListener('click', function(){
infowindow.setContent(this.content);
infowindow.open(map, this);
});
}
});
}
function createMarker(){
for (i=0; i < venues.length; i++){
doAjax(i);
}
}

You have a common problem caused by calling an asynchronous function inside a loop. One way to fix the issue (i is past the end of the input array when the callback functions run) is with a Immediately-Invoked Function Expression (IIFE) which holds closure on the i variable, so when the callback function is executed, it has the "correct" value:
success: (function(i) {
return function(data) {
text = data[2];
venueInfo = text[0];
console.log(venueInfo);
marker = new google.maps.Marker({
position: {
lat: venues[i].lat,
lng: venues[i].lng
},
map: map,
draggable: false,
content: '<h2>' + venues[i].name + '</h2><p>' + venueInfo + '</p>'
});
markerNames.push(venues[i].name);
markers.push(marker);
infowindow = new google.maps.InfoWindow({
content: this.content
});
marker.addListener('click', function() {
infowindow.setContent(this.content);
infowindow.open(map, this);
});
}
}(i))
proof of concept fiddle
(working) code snippet:
var map;
var marker;
var infowindow;
var wikiURL;
var i;
var text;
var venueInfo;
var markers = [];
var markerNames = [];
var wikiURLs = [];
var venueArray = [];
//The Model - Pro/Collegiate Stadiums in PGH, Pa.
var venues = [{
name: "PNC Park",
lat: 40.446855,
lng: -80.0056666
},
{
name: "Heinz Field",
lat: 40.4466765,
lng: -80.01576
},
{
name: "PPG Paints Arena",
lat: 40.439593,
lng: -79.989338
},
{
name: "Highmark Stadium",
lat: 40.4362358,
lng: -80.00959209999999
},
{
name: "Peterson Events Center",
lat: 40.443828,
lng: -79.962283
}
];
//marker creator
function createMarker() {
for (i = 0; i < venues.length; i++) {
wikiURL = 'https://en.wikipedia.org/w/api.php?action=opensearch&search=' + venues[i].name + '&format=json&callback=wikiCallback';
wikiURLs.push(wikiURL);
$.ajax({
url: wikiURL,
dataType: "jsonp",
success: (function(i) {
return function(data) {
text = data[2];
venueInfo = text[0];
console.log(venueInfo);
marker = new google.maps.Marker({
position: {
lat: venues[i].lat,
lng: venues[i].lng
},
map: map,
draggable: false,
content: '<h2>' + venues[i].name + '</h2><p>' + venueInfo + '</p>'
});
markerNames.push(venues[i].name);
markers.push(marker);
infowindow = new google.maps.InfoWindow({
content: this.content
});
marker.addListener('click', function() {
infowindow.setContent(this.content);
infowindow.open(map, this);
});
}
}(i))
});
}
}
//Map Initializer
function initMap() {
map = new google.maps.Map(document.getElementById('map'), {
center: {
lat: 40.446855,
lng: -80.0056666
},
zoom: 14,
mapTypeId: 'satellite'
});
//viewmodel();
createMarker();
}
html,
body,
#map {
height: 100%;
width: 100%;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<container>
<div id='map'>
</div>
</container>
<script type='text/javascript' async defer src="https://maps.googleapis.com/maps/api/js?callback=initMap">
</script>

Related

Cannot remove markers from google maps api

The markers in my program just wont remove with the deleteMarkers() function
CSS:
#map-canvas {
margin: 0;
padding: 0;
height: 100%;
}
HTML:
<div style="height:500px; width:750px;">
<div id="map-canvas"></div>
</div>
<select class="form-control" name="dateSelect" id="dateSelect" onchange="dateSelect_Event();"></select>
Javascript:
var map; <--- global variables
var locations = [];
var lat_get = '';
var long_get = '';
var marker=[];
var infowindow;
function initMap() {
map = new google.maps.Map(document.getElementById('map-canvas'), {
center: {lat: 7.072617, lng: 125.599494},
mapTypeId: google.maps.MapTypeId.ROADMAP,
zoom: 13,
});
};
function deleteMarkers() {
for (var i = 0; i < marker.length; i++ ) {
marker[i].setMap(null);
}
marker.length = 0;
}
function dateSelect_Event() {
deleteMarkers();
infowindow = new google.maps.InfoWindow({});
var locationsRef = firebase.database().ref("location");
locationsRef.on('child_added', function(snapshot) {
var data = snapshot.val();
marker = new google.maps.Marker({
position: {
lat: parseFloat(data.latitude),
lng: parseFloat(data.longitude)
},
map: map
});
marker.addListener('click', (function(data) {
return function(e) {
infowindow.setContent(this.getPosition().toUrlValue(6));
infowindow.open(map, this);
}
}(data)));
marker.setMap(map);
});
}
Firebase:
-databaseName
--location
---latitude
---longitude
I just use firebase to get the lat and long on every change of the html select option and it work perfectly. The problem this time is it can't delete the markers. Should I do the deleteMarkers differently?
Thanks to #StackSlave's answer. I was able to successfully remove it by creating and pushing the google_marker to the global marker variable.
function dateSelect_Event() {
deleteMarkers();
infowindow = new google.maps.InfoWindow({});
var locationsRef = firebase.database().ref("location");
locationsRef.on('child_added', function(snapshot) {
var data = snapshot.val();
var google_marker = new google.maps.Marker({
position: {
lat: parseFloat(data.latitude),
lng: parseFloat(data.longitude)
},
map: map
});
google_marker.addListener('click', (function(data) {
return function(e) {
infowindow.setContent(this.getPosition().toUrlValue(6));
infowindow.open(map, this);
}
}(data)));
marker.push(google_marker);
});
marker.setMap(map);
}

Google maps api cluster marker and custom info and icon

Im having a problem with custom icons. I have managed to get different infotext on the markers, i have managed to get the clusters to work, but when i add var icon1 and var icon2 and place them in the location array: "icon: icon2. All fails, is there a way to use both icon, infowindow and clustermarkers?
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no">
<meta charset="utf-8">
<title>Marker Clustering</title>
<style>
/* Always set the map height explicitly to define the size of the div
* element that contains the map. */
#map {
height: 100%;
}
/* Optional: Makes the sample page fill the window. */
html, body {
height: 100%;
margin: 0;
padding: 0;
}
</style>
</head>
<body>
<div id="map"></div>
<script>
function initMap() {
var map = new google.maps.Map(document.getElementById('map'), {
zoom: 10,
center: {lat: 63.418719, lng: 10.3685516}
});
var icon1 = {
url: "https://maps.google.com/mapfiles/kml/shapes/parking_lot_maps.png", // url
scaledSize: new google.maps.Size(50, 50), // size
};
var icon2 = {
url: "https://maps.google.com/mapfiles/kml/shapes/library_maps.png", // url
scaledSize: new google.maps.Size(50, 50), // size
};
var infoWin = new google.maps.InfoWindow();
var markers = locations.map(function(location, i) {
var marker = new google.maps.Marker({
position:location
});
google.maps.event.addListener(marker, 'click', function(evt) {
infoWin.setContent(location.info);
infoWin.open(map, marker);
})
return marker;
});
var markerCluster = new MarkerClusterer(map, markers,
{imagePath: 'https://developers.google.com/maps/documentation/javascript/examples/markerclusterer/m'});
}
var locations = [
{lat: 63.131623, lng: 10.370243, info:"Test1", icon: icon1},
{lat: 62.432600, lng: 10.300243, info:"Test2", icon: icon2},
{lat: 62.330642, lng: 10.300243, info:"Test2", icon: icon1},
{lat: 63.530691, lng: 10.300243, info:"Test2", icon: icon2},
]
</script>
<script src="https://developers.google.com/maps/documentation/javascript/examples/markerclusterer/markerclusterer.js">
</script>
<script async defer
src="https://maps.googleapis.com/maps/api/js?key=AIzoVQ&callback=initMap">
</script>
</body>
</html>
To actually use the icon in the locations array, change your marker definition from:
var markers = locations.map(function(location, i) {
var marker = new google.maps.Marker({
position:location
});
google.maps.event.addListener(marker, 'click', function(evt) {
infoWin.setContent(location.info);
infoWin.open(map, marker);
})
return marker;
});
To:
var markers = locations.map(function(location, i) {
var marker = new google.maps.Marker({
position: location,
icon: location.icon // <--------------------------------add this
});
google.maps.event.addListener(marker, 'click', function(evt) {
infoWin.setContent(location.info);
infoWin.open(map, marker);
})
return marker;
});
proof of concept fiddle
code snippet:
function initMap() {
var map = new google.maps.Map(document.getElementById('map'), {
zoom: 8,
center: {
lat: 63.418719,
lng: 10.3685516
}
});
var infoWin = new google.maps.InfoWindow();
var markers = locations.map(function(location, i) {
var marker = new google.maps.Marker({
position: location,
icon: location.icon
});
google.maps.event.addListener(marker, 'click', function(evt) {
infoWin.setContent(location.info);
infoWin.open(map, marker);
})
return marker;
});
var markerCluster = new MarkerClusterer(map, markers, {
imagePath: 'https://developers.google.com/maps/documentation/javascript/examples/markerclusterer/m'
});
}
var icon1 = {
url: "https://maps.google.com/mapfiles/kml/shapes/parking_lot_maps.png", // url
scaledSize: new google.maps.Size(50, 50), // size
};
var icon2 = {
url: "https://maps.google.com/mapfiles/kml/shapes/library_maps.png", // url
scaledSize: new google.maps.Size(50, 50), // size
};
var locations = [{
lat: 63.131623,
lng: 10.370243,
info: "Test1",
icon: icon1
}, {
lat: 62.432600,
lng: 10.300243,
info: "Test2",
icon: icon2
}, {
lat: 62.330642,
lng: 10.300243,
info: "Test2",
icon: icon1
}, {
lat: 63.530691,
lng: 10.300243,
info: "Test2",
icon: icon2
}, ]
google.maps.event.addDomListener(window, "load", initMap);
html,
body,
#map {
height: 100%;
width: 100%;
margin: 0px;
padding: 0px
}
<script src="https://maps.googleapis.com/maps/api/js?libraries=geometry,places&ext=.js"></script>
<script src="https://developers.google.com/maps/documentation/javascript/examples/markerclusterer/markerclusterer.js"></script>
<div id="map"></div>

Trouble populating infowindows with Zomato API data via $.ajax

I am trying to get the infowindows to populate with the Zomato API data, but I keep getting the last item in the object. I have tried a for loop with a closure and the for loop with "let" instead of "var", but this is not helping. Any suggestions that could push me forward would be greatly appreciated.
var map;
var markers = [];
var cuisines, name, establishment, locality, menu, photos, rating, infoContent;
var locations = [
{name: 'The Pub at Ghirardelli Square', latlng: {lat: 37.8063722222, lng: -122.4228888889}},
{name: 'The Irish Bank', latlng: {lat: 37.7902750000, lng: -122.4048472222}},
{name: 'Rogue San Francisco Public House', latlng: {lat: 37.8001440000, lng: -122.4104550000}},
{name: 'Chieftain Irish Restaurant & Pub', latlng: {lat: 37.7814900000, lng: -122.4051510000}},
{name: 'Kennedy\'s Irish Pub and Curry House', latlng: {lat: 37.8042510000, lng: -122.4156040000}},
{name: 'Murphy\'s Pub', latlng: {lat: 37.7901916667, lng: -122.4038472222}}
];
//create instance of a map from the Google Maps API
//Grab the reference to the "map" id to display the map
//Set the map options object properties
function initMap() {
map = new google.maps.Map(document.getElementById("map"), {
center: {
lat: 37.7884162,
lng: -122.4127457
},
zoom: 14
});
var infowindow = new google.maps.InfoWindow();
var marker;
for(var i = 0; i < locations.length; i++) {
(function() {
// get the position fronm the locations array
var position = locations[i].latlng;
var title = locations[i].name;
//create a marker per location and put into markers array
var marker = new google.maps.Marker({
map: map,
position: position,
title: title,
animation: google.maps.Animation.DROP
//id: i
});
//push the marker to our array of markers
markers.push(marker);
//extend the boundaries of the map for each marker
marker.addListener('click', function() {
populateInfoWindow(this, infowindow);
infowindow.setContent(infoContent);
});
})(i);//end of closure
}//end of for loop
}; //end initMap()
function populateInfoWindow(marker, infowindow) {
//check to make sure the infowindow is not already opened in this marker
if (infowindow.marker != marker) {
infowindow.marker = marker;
infowindow.setContent('<div>' + marker.title + '</div>' + marker.infoContent);
infowindow.open(map, marker);
//Make sure the marker property is cleared if the infowindow is closed
infowindow.addListener('closeclick', function() {
infowindow.setMarker = null;
});
}
}// end of populateInfoWindow
$.ajax({
method: "GET",
crossDomain: true,
url: "https://developers.zomato.com/api/v2.1/search?count=6&lat=37.79161&lon=-122.42143&establishment_type=6",
dataType: "json",
async: true,
headers: {
"user-key": "0a661374a6b58eb2fa84142d27fe81ca"
},
success: function(data) {
var pubs = [];
pubs = data.restaurants;
for(var j = 0; j < pubs.length; j++) {
(function(val) {
infoContent = "<div class='name'>" + "Pub: " + pubs[j].restaurant.name + "</div>" + "\n" + "<div class='cuisines'>" + pubs[j].restaurant.cuisines + "</div>";
})(j);
}
},
error: function() {
infoContent = "<div>Sorry, data is not coming through. Refresh and try again.</div>";
}
});//end of $.ajax call
<!doctype html>
<html class="no-js" lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Map</title>
<link rel="stylesheet" href="css/foundation.css">
<link rel="stylesheet" href="css/app.css">
</head>
<body>
<div class="grid-container">
<div class="grid-x grid-padding-x">
<div class="large-12 cell">
</div>
</div>
<div class="grid-x grid-padding-x">
<div class="large-12 cell">
<div class="callout">
<div id="map" class="flex-video">
<iframe width="420" height="315" src="" frameborder="0" allowfullscreen></iframe>
</div>
</div>
</div>
</div>
</div>
<script src="js/vendor/jquery.js"></script>
<script src="js/vendor/what-input.js"></script>
<script src="js/vendor/foundation.js"></script>
<script src="js/map.js"></script>
<script async deter src="https://maps.googleapis.com/maps/api/js?key=AIzaSyBS6v85DRLDI_VKGgNdgQ6EVzDxJfZZOF8&ve&3&libraries=places,drawing&callback=initMap">
</script>
</body>
</html>
The indicated line below is wrong, remove it and your code works:
marker.addListener('click', function() {
populateInfoWindow(this, infowindow);
// infowindow.setContent(infoContent); <<<<<<<<<<<< REMOVE
});
proof of concept fiddle
code snippet:
var map;
var markers = [];
var cuisines, name, establishment, locality, menu, photos, rating, infoContent;
var locations = [
{name: 'The Pub at Ghirardelli Square', latlng: {lat: 37.8063722222, lng: -122.4228888889}},
{name: 'The Irish Bank', latlng: {lat: 37.7902750000, lng: -122.4048472222}},
{name: 'Rogue San Francisco Public House', latlng: {lat: 37.8001440000, lng: -122.4104550000}},
{name: 'Chieftain Irish Restaurant & Pub', latlng: {lat: 37.7814900000, lng: -122.4051510000}},
{name: 'Kennedy\'s Irish Pub and Curry House', latlng: {lat: 37.8042510000, lng: -122.4156040000}},
{name: 'Murphy\'s Pub', latlng: {lat: 37.7901916667, lng: -122.4038472222}}
];
//create instance of a map from the Google Maps API
//Grab the reference to the "map" id to display the map
//Set the map options object properties
function initMap() {
map = new google.maps.Map(document.getElementById("map"), {
center: {
lat: 37.7884162,
lng: -122.4127457
},
zoom: 14
});
var infowindow = new google.maps.InfoWindow();
var marker;
for (var i = 0; i < locations.length; i++) {
(function() {
// get the position fronm the locations array
var position = locations[i].latlng;
var title = locations[i].name;
//create a marker per location and put into markers array
var marker = new google.maps.Marker({
map: map,
position: position,
title: title,
animation: google.maps.Animation.DROP,
infoContent: "there is no infoContent!"
//id: i
});
//push the marker to our array of markers
markers.push(marker);
//extend the boundaries of the map for each marker
marker.addListener('click', function() {
populateInfoWindow(this, infowindow);
});
})(i); //end of closure
} //end of for loop
}; //end initMap()
function populateInfoWindow(marker, infowindow) {
//check to make sure the infowindow is not already opened in this marker
if (infowindow.marker != marker) {
infowindow.marker = marker;
infowindow.setContent('<div>' + marker.title + '</div>' + marker.infoContent);
infowindow.open(map, marker);
//Make sure the marker property is cleared if the infowindow is closed
infowindow.addListener('closeclick', function() {
infowindow.setMarker = null;
});
}
} // end of populateInfoWindow
$.ajax({
method: "GET",
crossDomain: true,
url: "https://developers.zomato.com/api/v2.1/search?count=6&lat=37.79161&lon=-122.42143&establishment_type=6",
dataType: "json",
async: true,
headers: {
"user-key": "0a661374a6b58eb2fa84142d27fe81ca"
},
success: function(data) {
var pubs = [];
pubs = data.restaurants;
for (var j = 0; j < pubs.length; j++) {
(function(val) {
infoContent = "<div class='name'>" + "Pub: " + pubs[j].restaurant.name + "</div>" + "\n" + "<div class='cuisines'>" + pubs[j].restaurant.cuisines + "</div>";
})(j);
}
},
error: function() {
infoContent = "<div>Sorry, data is not coming through. Refresh and try again.</div>";
}
}); //end of $.ajax call
google.maps.event.addDomListener(window, "load", initMap);
html,
body,
#map {
height: 100%;
width: 100%;
margin: 0px;
padding: 0px
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://maps.googleapis.com/maps/api/js"></script>
<div id="map"></div>
The discovery to this answer is a good exercise in appreciating scope. I also discovered that my data object could ride the same iterator from the for loop for the markers.
//create instance of a map from the Google Maps API
//Grab the reference to the "map" id to display the map
//Set the map options object properties
function initMap() {
map = new google.maps.Map(document.getElementById("map"), {
center: {
lat: 37.7884162,
lng: -122.4127457
},
zoom: 14
});
var marker;
//$.ajax call
$.ajax({
method: "GET",
crossDomain: true,
url: "https://developers.zomato.com/api/v2.1/search?count=6&lat=37.79161&lon=-122.42143&establishment_type=6",
dataType: "json",
async: true,
headers: {
"user-key": "0a661374a6b58eb2fa84142d27fe81ca"
},
success: function(data) {
passZomatoData(data);
},
error: function() {
infoContent = "<div>Sorry, data is not coming through. Refresh and try again.</div>";
}
});//end of $.ajax call
//function passZomatoData()
function passZomatoData(data) {
var infowindow = new google.maps.InfoWindow();
pubs = data.restaurants;
console.log(data);
for(var i = 0; i < locations.length; i++) {
(function() {
// get the position fronm the locations array
var position = locations[i].latlng;
var title = locations[i].name;
var cuisine = pubs[i].restaurant.cuisines;
var address = pubs[i].restaurant.location.address;
console.log(address);
//create a marker per location and put into markers array
var marker = new google.maps.Marker({
map: map,
position: position,
title: title,
cuisine: cuisine,
address: address,
animation: google.maps.Animation.DROP
});
//push the marker to our array of markers
markers.push(marker);
//extend the boundaries of the map for each marker
marker.addListener('click', function() {
populateInfoWindow(this, infowindow);
infowindow.setContent('<div><b>Pub name:<b> ' + marker.title + '</div><div><b>Address:<b> ' + marker.address + '</div><div><b>Cuisine:<b> ' + marker.cuisine + '</div>');
});
})(i);//end of closure
}//end of for loop
}
}; //end initMap()
function populateInfoWindow(marker, infowindow) {
//check to make sure the infowindow is not already opened in this marker
if (infowindow.marker != marker) {
infowindow.marker = marker;
//infowindow.setContent('<div>' + marker.title + '</div>' + marker.infoContent);
infowindow.open(map, marker);
//Make sure the marker property is cleared if the infowindow is closed
infowindow.addListener('closeclick', function() {
infowindow.setMarker = null;
});
}
}// end of populateInfoWindow

Google Maps JS API + JSON - Multiple markers not showing up

So, what I need is very simple, I need to put markers in a map, I get the data from a JSON I built using PHP. I looked up all other questions(really) about Google Maps markers not showing up, and none of them worked for me. I can't find the flaw in my code.
The JSON is like this (but 58 items long), 'id' is unimportant:
[
{
"id": "2",
"lat": "-49.217290",
"lon": "-16.416160",
"tit": "Heinz",
"desc": "18 Machines"
},
{
"id": "3",
"lat": "-49.235455",
"lon": "-16.676926",
"tit": "Warehouse",
"desc": "10 Machines"
}
]
I'm new here, sorry if I do something wrong. My code is bellow:
<div id="map" class="height-400"></div>
<script>
var map;
var myLatLon = {lat: -16.398293, lng: -48.965098};
var markers = [];
$.ajax({
dataType:'json',
url: "contents/map_data.php",
success: function(data){
markers = data;
}
});
function initMap() {
map = new google.maps.Map(document.getElementById('map'), {
center: myLatLon,
zoom: 4,
//disableDefaultUI: true,
});
var i= 0;
$.each(markers, function(i, item) {
if(typeof item == 'object') {
var marker = new google.maps.Marker({
position: new google.maps.LatLng(parseFloat(item.lat),parseFloat(item.lon)),
map: map,
title: item.titulo,
label: item.desc
});
marker.setMap(map);
google.maps.event.addListener(marker, 'click', (function(marker, i) {
return function() {
infowindow.setContent(item.desc);
infowindow.open(map, marker);
}
})(marker, i));
i=i+1;
}
});
}
</script>
<script src="https://maps.googleapis.com/maps/api/js?key=MY_SECRET_KEY&callback=initMap" async defer></script>
Markers variable is an empty array, cause the AJAX request has not returned yet. You should either move your code inside success callback or invoke it from success callback.
Try something like:
<div id="map" class="height-400"></div>
<script>
var map;
var myLatLon = {lat: -16.398293, lng: -48.965098};
var markers = [];
$.ajax({
dataType:'json',
url: "contents/map_data.php",
success: function(data){
markers = data;
initMap();
}
});
function initMap() {
map = new google.maps.Map(document.getElementById('map'), {
center: myLatLon,
zoom: 4,
//disableDefaultUI: true,
});
var i= 0;
$.each(markers, function(i, item) {
if(typeof item == 'object') {
var marker = new google.maps.Marker({
position: new google.maps.LatLng(parseFloat(item.lat),parseFloat(item.lon)),
map: map,
title: item.titulo,
label: item.desc
});
marker.setMap(map);
google.maps.event.addListener(marker, 'click', (function(marker, i) {
return function() {
infowindow.setContent(item.desc);
infowindow.open(map, marker);
}
})(marker, i));
i=i+1;
}
});
}
</script>
<script src="https://maps.googleapis.com/maps/api/js?key=MY_SECRET_KEY&callback=initMap" async defer></script>

Google Maps V3 infowindows displaying wrong content on pins

I am plotting addresses and having an issue with the infowindow showing the right content everytime. Sometimes it shows the right content in the infowindow when clicked and sometimes it shows the wrong information for that map pin.
var map = null;
var markersArray = [];
var markers = [];
var openedInfoWindow ="";
var geocoder = new google.maps.Geocoder();
function initialize() {
var mapOptions = {
zoom: 8,
center: new google.maps.LatLng(64.85599578876611, -147.83363628361917),
mapTypeId: google.maps.MapTypeId.ROADMAP
};
map = new google.maps.Map(document.getElementById("mapInfoManual"),
mapOptions);
google.maps.event.addListener(map, 'zoom_changed', function() {
zoomChangeBoundsListener = google.maps.event.addListener(map, 'bounds_changed', function(event) {
if (this.getZoom() > 20) // Change max/min zoom here
this.setZoom(18);
google.maps.event.removeListener(zoomChangeBoundsListener);
});
});
addMarker();
}
function addMarker() {
var bounds = new google.maps.LatLngBounds();
for(i=0; i<markersArray.length; i++)
{
CodeAddress(markersArray[i]['address']);
var mytitle = (markersArray[i]['title']);
var myaddress = (markersArray[i]['displayaddress']);
var linkurl = (markersArray[i]['linkurl']);
}
setTimeout(function()
{
for(i=0; i<markers.length; i++)
{
var point = new google.maps.LatLng(markers[i]['lat'], markers[i]['lng']);
var marker = new google.maps.Marker({
position: point,
map: map
});
bounds.extend(point);
var infoWindowContent = "<div style='padding:2px;'><div style='margin-bottom:5px;font-weight:700;color:#033551;'>"+ mytitle +"</div><div style='margin-bottom:5px;'>" + myaddress + "</div><div><a href='" + linkurl + "/'>More Details</a></div></div>";
openInfoWindow(marker,infoWindowContent)
}
map.fitBounds(bounds);
},2500);
}
// Address To Marker
function CodeAddress(address)
{
geocoder.geocode( { 'address': address}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
lat = results[0].geometry.location.lat();
lng = results[0].geometry.location.lng();
markers.push({
'lat':lat,
'lng':lng,
'address':address
});
}
});
}
//Info Window
function openInfoWindow(marker,infoWindowContent)
{
var infowindow = new google.maps.InfoWindow({
content: '<div class="cityMapInfoPop">'+infoWindowContent+'</div>'
});
google.maps.event.addListener(marker, 'click', function() {
if(openedInfoWindow !="")
{
openedInfoWindow.close()
}
infowindow.open(map,marker);
openedInfoWindow = infowindow;
});
}
Variables that I pass in:
<script type="application/javascript">
markersArray.push({
"title":'<?php echo $maptitle;?>',
"address":'<?php echo $markerAddress;?>',
"displayaddress":'<?php echo $displayAddress;?>',
"linkurl":'<?php echo $addressUrl;?>'
});
</script>
Your issue is that geocoding is asynchronous. You loop through calling the geocoder on all your addresses, but the order the results are returned in is not predictable.
use function closure to associate the marker with the infowindow
use function closure to associate the address with the marker
use the results of the geocoder inside its callback function.
Note that if you have more that approximately 10 markers in your array you will run into the quota/rate limit of the geocoder.
proof of concept fiddle
code snippet:
var map = null;
var markersArray = [];
var markers = [];
var openedInfoWindow = "";
var geocoder = new google.maps.Geocoder();
var bounds = new google.maps.LatLngBounds();
markersArray.push({
"title": 'marker 0',
"address": 'New York,NY',
"displayaddress": 'New York, NY',
"linkurl": 'http://google.com'
});
markersArray.push({
"title": 'marker 1',
"address": 'Boston, MA',
"displayaddress": 'Boston, MA',
"linkurl": 'http://yahoo.com'
});
markersArray.push({
"title": 'marker 2',
"address": 'Newark,NJ',
"displayaddress": 'Newark, NJ',
"linkurl": 'http://mapquest.com'
});
google.maps.event.addDomListener(window, "load", initialize);
function initialize() {
var mapOptions = {
zoom: 8,
center: new google.maps.LatLng(64.85599578876611, -147.83363628361917),
mapTypeId: google.maps.MapTypeId.ROADMAP
};
map = new google.maps.Map(document.getElementById("mapInfoManual"),
mapOptions);
google.maps.event.addListener(map, 'zoom_changed', function() {
zoomChangeBoundsListener = google.maps.event.addListener(map, 'bounds_changed', function(event) {
if (this.getZoom() > 20) // Change max/min zoom here
this.setZoom(18);
google.maps.event.removeListener(zoomChangeBoundsListener);
});
});
addMarker();
}
function addMarker() {
var bounds = new google.maps.LatLngBounds();
for (i = 0; i < markersArray.length; i++) {
CodeAddress(markersArray[i]);
}
}
// Address To Marker
function CodeAddress(markerEntry) {
var mytitle = (markerEntry['title']);
var myaddress = (markerEntry['displayaddress']);
var linkurl = (markerEntry['linkurl']);
geocoder.geocode({
'address': markerEntry['address']
}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
var marker = new google.maps.Marker({
position: results[0].geometry.location,
map: map
});
bounds.extend(marker.getPosition());
var infoWindowContent = "<div style='padding:2px;'><div style='margin-bottom:5px;font-weight:700;color:#033551;'>" + mytitle + "</div><div style='margin-bottom:5px;'>" + myaddress + "</div><div><a href='" + linkurl + "/'>More Details</a></div></div>";
openInfoWindow(marker, infoWindowContent);
markers.push(marker);
map.fitBounds(bounds);
} else {
alert("geocode failed: " + status);
}
});
}
//Info Window
function openInfoWindow(marker, infoWindowContent) {
var infowindow = new google.maps.InfoWindow({
content: '<div class="cityMapInfoPop">' + infoWindowContent + '</div>'
});
google.maps.event.addListener(marker, 'click', function() {
if (openedInfoWindow != "") {
openedInfoWindow.close();
}
infowindow.open(map, marker);
openedInfoWindow = infowindow;
});
}
html,
body,
#mapInfoManual {
height: 500px;
width: 500px;
margin: 0px;
padding: 0px
}
<script src="https://maps.googleapis.com/maps/api/js?ext=.js"></script>
<div id="mapInfoManual" style="border: 2px solid #3872ac;"></div>
Since you didn't provide a working JSFiddle, it was rather difficult to figure out what your problem is. That said, you can look at this JSFiddle that I made for you to review what I'm doing, vs what you're doing.
Why are you using setTimeout() to place your markers? Also, you may have better results if you create an individual infoWindow per marker, instead of using a "global" infoWindow (which is what it looks like you're doing).
If you edit your post to add a working example of your problem, I can help further.
window.places = [{
title: "foo",
address: {
lat: parseFloat("64.85599578876611"),
lng: parseFloat("-147.83363628361917")
},
displayAddress: "101 BLVD",
linkURL: "google.com"
}, {
title: "bar",
address: {
lat: parseFloat("62.85599578876611"),
lng: parseFloat("-147.83363628361917")
},
displayAddress: "202 BLVD",
linkURL: "images.google.com"
}, ]
function initialize() {
"use strict";
var myLatlng = new google.maps.LatLng(window.places[0].address.lat, window.places[0].address.lng),
mapOptions = {
zoom: 4,
center: myLatlng
};
window.map = new google.maps.Map(document.getElementById('map-canvas'), mapOptions);
$.each(window.places, function(i) {
var infowindow = new google.maps.InfoWindow({
content: "<div style='padding:2px;'><div style='margin-bottom:5px;font-weight:700;color:#033551;'>" + window.places[i].title + "</div><div style='margin-bottom:5px;'>" + window.places[i].displayAddress + "</div><div><a href='" + window.places[i].linkURL + "/'>More Details</a></div></div>"
}),
marker = new google.maps.Marker({
position: new google.maps.LatLng(window.places[i].address.lat, window.places[i].address.lng),
map: window.map,
title: window.places[i].title
});
google.maps.event.addListener(marker, 'click', function() {
infowindow.open(window.map, marker);
});
});
}
google.maps.event.addDomListener(window, 'load', initialize);
html,
body,
#map-canvas {
height: 100%;
margin: 0px;
padding: 0px
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://maps.googleapis.com/maps/api/js?v=3.exp&signed_in=true"></script>
<div id="map-canvas"></div>

Categories

Resources