Welcome to the Treehouse Community
Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.
Looking to learn something new?
Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.
Start your free trial

benfarnham
17,073 PointsUsing Google Maps API with Dynamic Data To Populate Markers & InfoWindows.
So I am trying to create a Google Map that loops through content posted on the webpage (input is from a CMS that populates data-attributes) and at the end of the loop, creates a marker for each address and each address has it's own infowindow so a user can click on the marker, view the property and click through to the link associated.
I honestly feel like I am so close as I have the map populating, and infowindows appearing BUT the windows loop through every property attribute given (i.e. you click on a window and close it but then the next property appears so you close it then the next appears, so on, so forth).
I have the HTML set like so:
<div data-address="Address Goes Here" data-bedroom="Bedroom Count Here" databathroom="Bathroom Count Goes Here etc"></div>
<div data-address="Address Goes Here" data-bedroom="Bedroom Count Here" databathroom="Bathroom Count Goes Here etc"></div>
<div data-address="Address Goes Here" data-bedroom="Bedroom Count Here" databathroom="Bathroom Count Goes Here etc"></div>
And I have the JavaScript like so to loop through each div in a row and pull from the provided data attributes.
var map;
var geocoder;
var mark;
function init() {
var customMapType = new google.maps.StyledMapType([{"featureType":"administrative","elementType":"labels.text.fill","stylers":[{"color":"#444444"}]},{"featureType":"landscape","elementType":"all","stylers":[{"color":"#f2f2f2"}]},{"featureType":"poi","elementType":"all","stylers":[{"visibility":"off"}]},{"featureType":"road","elementType":"all","stylers":[{"saturation":-100},{"lightness":45}]},{"featureType":"road.highway","elementType":"all","stylers":[{"visibility":"simplified"}]},{"featureType":"road.arterial","elementType":"labels.icon","stylers":[{"visibility":"off"}]},{"featureType":"transit","elementType":"all","stylers":[{"visibility":"off"}]},{"featureType":"water","elementType":"all","stylers":[{"color":"#46bcec"},{"visibility":"on"}]}], {
name: 'Custom Map'
});
var customMapTypeId = 'custom_map';
var adrsLength = document.querySelectorAll('[data-show-map]');
map = new google.maps.Map(document.getElementById("property-map"), {
zoom: 5,
center: {lat: 38.6193592, lng: -95.7215047},
mapTypeControlOptions: {
mapTypeIds: [google.maps.MapTypeId.ROADMAP, customMapTypeId]
}
});
map.mapTypes.set(customMapTypeId, customMapType);
map.setMapTypeId(customMapTypeId);
geocoder = new google.maps.Geocoder();
for(var i = 0, num = adrsLength.length; i < num; i++) {
geocoder.geocode({
'address': adrsLength[i].dataset.address
}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
mark = new google.maps.Marker({
position: results[0].geometry.location,
map: map
});
map.setCenter(results[0].geometry.location);
setInfoWindow();
}
});
} // End Geocode
function setInfoWindow() {
google.maps.event.addListener(mark, 'click', function(event) {
for(var i = 0, num = adrsLength.length; i < num; i++) {
var iwindow = new google.maps.InfoWindow();
iwindow.setContent('<div id="info-bubble" style="padding:20px;border-radius:5px;max-width:260px;box-shadow:none;"><a href="' + adrsLength[i].dataset.url + '" style="display:block;"><img src="' + adrsLength[i].dataset.thumbnail + '" style="display:block;margin-bottom:10px;max-width:100%;"></a><h4>' + adrsLength[i].dataset.address + '</h4><p>Bedrooms: ' + adrsLength[i].dataset.bedroom + '<br />Bathrooms: ' + adrsLength[i].dataset.bathroom + '<br /><span>' + adrsLength[i].dataset.price + '</span></p></div>');
iwindow.open(map, this);
}
});
}
}
window.onload = init;
So, I feel like I am very close but for some reason I am stumped on the last section. I feel like I need to make a separate function that ties each marker with the info window but then I am lost as to how I might do that.
I would really like to see how I can do this so any insights would be really appreciated!
3 Answers

Iain Simmons
Treehouse Moderator 32,305 PointsI'd say it's because you're calling the setInfoWindow
function on each iteration of the loop, then looping again within the setInfoWindow
. Try passing an index to the setInfoWindow
function instead, removing the loop in that function, and using that for the HTML in the iwindow.setContent
method call:
function setInfoWindow(idx) {
google.maps.event.addListener(mark, 'click', function(event) {
var iwindow = new google.maps.InfoWindow();
iwindow.setContent('<div id="info-bubble" style="padding:20px;border-radius:5px;max-width:260px;box-shadow:none;"><a href="' + adrsLength[idx].dataset.url + '" style="display:block;"><img src="' + adrsLength[idx].dataset.thumbnail + '" style="display:block;margin-bottom:10px;max-width:100%;"></a><h4>' + adrsLength[idx].dataset.address + '</h4><p>Bedrooms: ' + adrsLength[idx].dataset.bedroom + '<br />Bathrooms: ' + adrsLength[idx].dataset.bathroom + '<br /><span>' + adrsLength[idx].dataset.price + '</span></p></div>');
iwindow.open(map, this);
});
}
Note that adrsLength
is probably not an appropriate name for the collection of elements containing the addresses... but it's probably a better choice for the length variable in your first loop. Maybe addresses
would be fine for the collection, and addressesLength
would be clearer for the length variable? Anyways, that's up to you.

Rhett Herring
Courses Plus Student 11,023 PointsI have done something sort of similar maybe it will help:
I get some json then do a .each and populate my markers.
$.ajax({
type: "GET",
dataType: "json",
url: getURL,
success: function (result) {
if (result.length) {
$.each(result, function (i, v) {
$(".js-region-hotspots").append("<option value=" + v.lng + "," + v.lat + ">" + v.locName + </option");
var myLatlng = new google.maps.LatLng(v.lat, v.lng);
function getPrettyDate(_date) {
return prettyDate(_date);
}
var contentString = '<div id="content"><strong>' + v.comName + ' (' + v.howMany + ')' + '</strong><br/>Lat:' + v.lat + ' Long:' + v.lng + '<br/>' + v.locName + '<br/>' + moment(v.obsDt).format('LLL') + ' -- ' + getPrettyDate(v.obsDt) + '</div><br/>' + "<button type=\"button\" class=\"k-button\" onclick=\"getDirectionsLatLng(" + v.lat + "," + v.lng + ")\">Get Directions</button>";
var infowindow = new google.maps.InfoWindow({
content: contentString
});
var marker = new google.maps.Marker({
position: myLatlng,
map: map,
title: v.locName,
animation: google.maps.Animation.DROP,
icon: "images/redBird.gif"
});
markers.push(marker);
marker.addListener('click', function () {
infowindow.open(map, marker);
//alert(marker.position);
});
});
Hope it helps.

benfarnham
17,073 PointsI actually broke it down and it was because I was looping the setting of the 'infowindow' inside of the loop placing the markers. To fix it, I separated the placing of markers and the infowindows into their on function and then placed the function inside of one 'for' loop.
Lol I commented everything out and broke it up into easier chunks for myself.
Here was the result I came up with:
var map;
var geocoder;
var mark;
// Map Initialization Function
function init() {
// Target All Of The Property Data Attributes For Future 'For' Loop
var adrsLength = document.querySelectorAll('[data-show-map]');
// Customized Google Map Style
var customMapType = new google.maps.StyledMapType([{"featureType":"administrative","elementType":"labels.text.fill","stylers":[{"color":"#444444"}]},{"featureType":"landscape","elementType":"all","stylers":[{"color":"#f2f2f2"}]},{"featureType":"poi","elementType":"all","stylers":[{"visibility":"off"}]},{"featureType":"road","elementType":"all","stylers":[{"saturation":-100},{"lightness":45}]},{"featureType":"road.highway","elementType":"all","stylers":[{"visibility":"simplified"}]},{"featureType":"road.arterial","elementType":"labels.icon","stylers":[{"visibility":"off"}]},{"featureType":"transit","elementType":"all","stylers":[{"visibility":"off"}]},{"featureType":"water","elementType":"all","stylers":[{"color":"#46bcec"},{"visibility":"on"}]}], {
name: 'Custom Map'
});
var customMapTypeId = 'custom_map';
// Creating The New Google Map
map = new google.maps.Map(document.getElementById("property-map"), {
// Setting Map Options
zoom: 5,
center: {lat: 38.6193592, lng: -95.7215047},
mapTypeControlOptions: {
mapTypeIds: [google.maps.MapTypeId.ROADMAP, customMapTypeId]
}
});
// Appending New Map Styles
map.mapTypes.set(customMapTypeId, customMapType);
map.setMapTypeId(customMapTypeId);
// Loop 'setInfoWindow' creating map points and infowindows
for(var i = 0, num = adrsLength.length; i < num; i++) {
setInfoWindow(i)
}
// Geocoding addresses and appending infowindows
function setInfoWindow(i) {
geocoder = new google.maps.Geocoder();
// Finding the Latitude / Longitude of the given address
geocoder.geocode({
'address': adrsLength[i].dataset.address
}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
mark = new google.maps.Marker({
position: results[0].geometry.location,
map: map
});
google.maps.event.addListener(mark, 'click', function(event) {
// Appends infowindow to the Google map mark
var iwindow = new google.maps.InfoWindow({
content: '<div id="info-bubble" style="padding:16px;border-radius:5px;max-width:260px;box-shadow:none;"><a href="' + adrsLength[i].dataset.url + '" style="display:block;"><img src="' + adrsLength[i].dataset.thumbnail + '" style="display:block;margin-bottom:10px;max-width:100%;"></a><h4>' + adrsLength[i].dataset.address + ' - <span>' + adrsLength[i].dataset.price + '</span></h4><p>Bedrooms: ' + adrsLength[i].dataset.bedroom + '<br />Bathrooms: ' + adrsLength[i].dataset.bathroom + '</p></div>'
});
iwindow.open(map, this);
});
}
});
}
}
// Call Initialization Function
window.onload = init;
benfarnham
17,073 Pointsbenfarnham
17,073 PointsYour correct about my loops! As for the name, that was just for my reference. I can clean up variable names later for easier access via future development.
Thanks a bunch!