Tag Archives: Google Maps

How to show an InfoWindow for multiple Markers using Google Maps v3

Recently I have been working on an interactive map for the City of Aliso Viejo, CA using Google Maps.   I chose to use version 3 of the Google Maps API, because version 2 was deprecated on May 19, 2010.  I was happy to discover I no longer needed an API.  However, I did not anticipate how the changes to the MVC framework affected things.  My first task was to display multiple markers on a map, each marker having its own InfoWindow.  I found plenty of v2 examples, but could not find a really good v3 example.   Here is my solution to showing an InfoWindow for multiple markers using Google Maps v3.

In v2 GInfoWindow does not have a constructor, so an info window is displayed by calling openInfoWindow() or openInfoWindowHtml() on the GMap2 object.

GEvent.addListener(marker, 'click', function() {
    var markerPosn = new GLatLng(place["posn"][0], place["posn"][1]);
    map.openInfoWindowHtml(markerPosn ,buildPlaceInfoHtml(place),{maxWidth:275});
}); 

Things have changed significantly in Google Maps v3.  The InfoWindow now has a constructor and openInfoWindow()or openInfoWindowHtml() have been removed.  Initially I was lost trying to get each marker to show an InfoWindow with its own content.    I then read the following from the Google Maps v3 documentation about InfoWindow overlays.

InfoWindows may be attached to either Marker objects (in which case their position is based on the marker’s location) or on the map itself at a specified LatLng. If you only want one info window to display at a time (as is the behavior on Google Maps), you need only create one info window, which you can reassign to different locations or markers upon map events (such as user clicks).

Realizing I only needed one InfoWindow object. I refactored my code to create a single InfoWindow and then set  the InfoWindow content when a marker was clicked and then attach it to the appropriate marker.

var infoWindow = new google.maps.InfoWindow({});
var markers = new Array(); 

function setMarkers(map, locations, areaId) {
     for(var i = 0; i < locations.length; i++) {
         var location = locations[i];
         var latlng = new google.maps.LatLng(location.Location[0], location.Location[1]);
         var marker = new google.maps.Marker({
             position: latlng,
             map: map,
             shadow: createMarkerShadow(location.MarkerShadow),
             icon: createMarkerImage(location.MarkerImage),
             shape: markerShape,
             title: location.Name
         });
         marker.set('location', location);
         google.maps.event.addListener(marker, "click", function(event) {
            var area = this.get('location');           
            var infoWindowHtml = parseTemplate($("#MarkerTemplate").html(), { location : location} );
            infoWindow.setContent(infoWindowHtml);
            infoWindow.open(map, this);
         });
         markers.push(marker);
     }
}

function clearMarkers() {
     infoWindow.close();
     for(var i = 0; i < markers.length; i++) {
         markers[i].setMap(null);
     }
     markers.length = 0;
}

This new code iterates through an array of locations and creates a marker for each, attaches the location object, and adds an click event listener to each marker.  Attaching the location object to the marker is the key to changing the InfoWindow content when the marker is clicked. 

marker.set('location', location);

This is made possible because the InfoWindow is built on the MVCObject prototype, which exposes accessor methods.  When a marker click event fires the location object can be retrieve using the get accessor.  Now the content of the InfoWindow can be updated from the location object and attached to the marker that was clicked.

 google.maps.event.addListener(marker, "click", function(event) {
    var area = this.get('location');           
    var infoWindowHtml = parseTemplate($("#MarkerTemplate").html(), { location : location} );
    infoWindow.setContent(infoWindowHtml);
    infoWindow.open(map, this);
 });