Posted by & filed under Web Development.

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);
 });

7 Responses to “How to show an InfoWindow for multiple Markers using Google Maps v3”

  1. Richard

    Nice example, thanks. What’s going on with this line, however? I can’t find this function:

    parseTemplate($(“#MarkerTemplate”).html(), { location : location} )

  2. aaron

    The parseTemplate function parses a template containing binding expressions. The template is applied to data object, and returned as a string of markup to be rendered into the DOM or in this case the info window’s content. You may want to look at jQuery template instead of this custom template method.

    The template is embedded in the source of the page in a script block and uses ‘< #= #>‘ to define the data binding expressions.


    <script id="MarkerTemplate" type="text/x-jquery-tmpl">
    <div class="av-areaInfo">
    <h3><#= area.Name #></h3>
    <div class="av-areaInfoImage">
    <# if (area.Images[0]) { #>
    <img src="<#= area.Images[0] #>" alt="<#= area.Name #>" />
    <# } #>
    </div>
    <p>
    <# if (area.Description.length > 0) { #>
    <#= area.Description #><br><br>
    <# } #>
    Directions: <a href="http://www.google.com/maps?daddr=<#= area.Latitude # rel="nofollow">,<#= area.Longitude#>&mrsp=0" target="_blank">To here</a> - <a href="http://www.google.com/maps?saddr=<#= area.Latitude # rel="nofollow">,<#= area.Longitude#>&mrsp=0" target="_blank">From here</a>
    </p>
    </div>
    </script>

    Here is the JavaScript for parseTemplate:


    this.parseTemplate = function(str, data) {
    var err = "";
    try {
    var func = _tmplCache[str];
    if (!func) {
    var strFunc =
    "var p=[],print=function(){p.push.apply(p,arguments);};" +
    "with(obj){p.push('" +
    str.replace( /[\r\t\n]/g , " ")
    .replace( /'(?=[^#]*#>)/g , "\t")
    .split("'").join("\\'")
    .split("\t").join("'")
    .replace( /< #=(.+?)#>/g , "',$1,'")
    .split("< #").join("');") .split("#>").join("p.push('")
    + "');}return p.join('');";

    //alert(strFunc);
    func = new Function("obj", strFunc);
    _tmplCache[str] = func;
    }
    return func(data);
    } catch(e) {
    err = e.message;
    }
    return "< # ERROR: " + err + " # >";
    };

  3. blake

    This is excellent, thank you for sharing – I am having trouble putting it all together – would you mind showing a fully functional example map, I’m new to javascript on the whole, but I have constructed a map and placed custom markers on it – I want to make the info windows appear with the “onmouseover” event and send the user to a unique URL on a marker click…

  4. patrick

    Thank you very much – it wasnt clear how to do this until I found your post. Just a quick note, in case it throws anyone else off, a typo on line 18:

    var area = this.get(‘location’);

    should be

    var location = this.get(‘location’);

  5. Pat.M

    Thanks, this is nice…
    But a link to a functioning example would be good, it will make it clearer as to the function of some of the variables.
    … I too am having trouble implementing this on my maps.

  6. Szylla

    I want to show the Infowindow of the first marker when I open the map. Has anyone an idea to do this?

Trackbacks/Pingbacks

  1.  Tweets that mention aaronkjackson.com » How to show an InfoWindow for multiple Markers using Google Maps v3 -- Topsy.com

Leave a Reply

  • (will not be published)