Google Maps: Adding Multiple Markers each with their own InfoWindow

Adding a map to a webpage is easy to do and is an expected feature these days. Adding static Google maps is simple, but when a customer asked me to display a map with multiple markers that are clickable and link to another URL I was surprised that it was more difficult than first seems.

The problem was that when I added all the markers the labels worked fine, but when I clicked on the marker I always got the  last value I added, i.e. all the links were the same.

With the help of the internet and many people who understood the problem better than me, I read the problem lies in closures. I’m not going into detail here but the idea to get it working is that you call a separate function to add the marker and the listener.

Here’s the code of an example. I’ve centered the map around Birmingham (UK) and added the controls (zoom and other options). In the actual site I created the location list dynamically with a bit of PHP, but you get the idea and I hope it helps.

<style>
 #map-canvas {margin:0;padding:0;border: 1px solid #000;
    width:600px;height:300px;}
 .mappop a{width:auto;color:black;background-color:white;padding:3px;
    text-decoration:underline;}
 </style>
<div id="map-canvas"></div>
<script src="https://maps.googleapis.com/maps/api/js?v=3.exp&sensor=false">
</script>
<script>
 var infowindow = null;
 var locs = [
 ['Birmingham Uni', 52.4489717, -1.9308602, 'http://www.birmingham.ac.uk'],
 ['Bham City Uni', 52.5172711, -1.8972868, 'http://www.bcu.ac.uk/'],
 ['Aston Uni', 52.4866368, -1.890952, 'http://www1.aston.ac.uk']
 ];
function add_marker(latLng, placename, map, note)
{
 var info_window = new google.maps.InfoWindow({
 content: '?'
 });
var marker = new google.maps.Marker({
 position: latLng,
 map: map,
 title: placename,
 clickable: true
 });
marker.note = note;
 google.maps.event.addListener(marker, 'click', function() {
 info_window.content = this.note;
 info_window.open(this.getMap(), this);
 });
 return marker;
}
function setMarkers(map, locations)
{
 for (var i = 0; i < locations.length; i++) {
var loc = locations[i];
 var myLatLng = new google.maps.LatLng(loc[1], loc[2]);
add_marker(myLatLng, loc[0], map,
 "<div class='mappop'>
    <a target='_blank' href='"+loc[3]+"'>"+loc[0]+"</a></div>");
 }
}
function initialize()
 {
 var mapOptions = {
 zoom: 11,
 center: new google.maps.LatLng(52.486243, -1.890401),
 mapTypeControl: true,
 mapTypeControlOptions: {
 style: google.maps.MapTypeControlStyle.HORIZONTAL_BAR,
 position: google.maps.ControlPosition.BOTTOM_CENTER
 },
 panControl: true,
 panControlOptions: {
 position: google.maps.ControlPosition.TOP_RIGHT
 },
 zoomControl: true,
 zoomControlOptions: {
 style: google.maps.ZoomControlStyle.LARGE,
 position: google.maps.ControlPosition.LEFT_CENTER
 },
 scaleControl: true,
 streetViewControl: true,
 streetViewControlOptions: {
 position: google.maps.ControlPosition.LEFT_TOP
 }
 };
var map = new google.maps.Map(document.getElementById('map-canvas'), 
    mapOptions);
 setMarkers(map, locs);
 }
google.maps.event.addDomListener(window, 'load', initialize);
</script>

The output looks like this after clicking the links:
gmap