My lack of javascript knowledge is really becoming a pain in the ass. I was trying to add multiple markers and infowindows via Google Maps v3 API, and whichever marker I clicked on, it would always open the infowindow of the last marker. Here is the code I was using:
//photoMarkers is a JavaScript array of objects that PHP spits out to the page, and the script below is from an external javascript file and is contained within a function
for (var i = 0; i < photoMarkers.length; i++) {
var p = photoMarkers[i];
var marker = new google.maps.Marker({position: new google.maps.LatLng(p.latitude, p.longitude), title: p.alt, map: map, draggable: true});
var infowindow = new google.maps.InfoWindow({content: p.content});
google.maps.event.addListener(marker, 'click', function() {
infowindow.open(map, marker);
});
}
I was baffled as to why this didn't work. I am creating new variables on every loop and then passing the marker to the infowindow via a closure. After some searching, I found a
solution which worked. But it still didn't explain why this wasn't working. Surely the Google code must be doing something strange in the addListener function, making my life difficult? Some more searching resulted in
this article, explaining why you can't have closures in loops. The closure is using the scope of the function it was created in and not the loop.Therefore each closure is "sharing" the variables, and when the closure is executed, it has a reference to the last marker and infowindow. Shows how little I know about JavaScript.
Another way of dealing with this is to return an anonymous function that acts as a closure from within another function. Now the closure, e.g. the inner function, takes the environment of the outer function on each loop, and it doesn't "share" the scope/environment with the other closures. E.g.
function infoCallback(infowindow, marker) {
return function() {
infowindow.open(map, marker);
};
}
for (var i = 0; i < photoMarkers.length; i++) {
var p = photoMarkers[i];
var marker = new google.maps.Marker({position: new google.maps.LatLng(p.latitude, p.longitude), title: p.alt, map: map, draggable: true});
var infowindow = new google.maps.InfoWindow({content: p.content});
google.maps.event.addListener(marker, 'click', infoCallback(infowindow, marker));
}