Adding Multiple Markers to Google Maps from JSON

Recently I’ve been receiving several emails from readers of my book, Beginning Google Maps API 3, that has a problem adding information to multiple InfoWindows when loading markers dynamically via JSON data.

In my book I have in fact described how to add multiple markers from JSON and how to attach unique InfoWindows to each of them. What I haven’t described is how to get the JSON-data to actually show up in the InfoWindows. This tutorial aims to describe how to do just that.

The JSON

In this example I’m going to use the capitals of the Scandinavian countries: Stockholm, Oslo and Copenhagen. Each capital will be displayed on the map with a marker. When you click a marker an InfoWindow will popup with some brief information about the city.

The JSON data looks like this:

var json = [
  {
    "title": "Stockholm",
    "lat": 59.3,
    "lng": 18.1,
    "description": "Stockholm is the capital and the largest city of Sweden and constitutes the most populated urban area in Scandinavia with a population of 2.1 million in the metropolitan area (2010)"
  },
  {
    "title": "Oslo",
    "lat": 59.9,
    "lng": 10.8,
    "description": "Oslo is a municipality, and the capital and most populous city of Norway with a metropolitan population of 1,442,318 (as of 2010)."
  },
  {
    "title": "Copenhagen",
    "lat": 55.7,
    "lng": 12.6,
    "description": "Copenhagen is the capital of Denmark and its most populous city, with a metropolitan population of 1,931,467 (as of 1 January 2012)."
  }
]

Note that the JSON data above contains the following information:

  • A Title in plain text
    We will use this information for a tooltip on the marker
  • A Latitude
    For the latitude portion of the position
  • A Longitude
    For the longitude portion of the position
  • A Description
    The content that will be displayed in the InfoWindows. I’ve included some HTML in it to illustrate that you’re not restricted to just plain text.

Note: In this example I have the JSON data in the same js file as the code, but in a real-life scenario you would probably grab it from an external source such as a back-end server or a web service.

Creating the map

First of all we need to create a map. The map will be centered over Scandinavia so that both Stockholm, Oslo and Copenhagen are visible.

// Creating a new map
var map = new google.maps.Map(document.getElementById("map"), {
  center: new google.maps.LatLng(57.9, 14.6),
  zoom: 6,
  mapTypeId: google.maps.MapTypeId.ROADMAP
});

If you feel unsure how this all works I recommend that you read Google Maps API 3 – The basics. It describes how to create a simple map.

Adding Markers

To create markers from the JSON-data we need to loop through it and extract the information for each marker.

for (var i = 0, length = json.length; i < length; i++) {
  var data = json[i],
      latLng = new google.maps.LatLng(data.lat, data.lng); 

  // Creating a marker and putting it on the map
  var marker = new google.maps.Marker({
    position: latLng,
    map: map,
    title: data.title
  });
}

This will add markers to the map and they will all have their own unique title which will show up as a tooltip when you hover over them with the mouse.

Adding InfoWindows

Ok, so now we've created a map and added some markers from JSON data. So far it hasn't been that hard, the way of doing this is pretty straight-forward. But to attach the InfoWindows properly is a different story. It's now that it starts to get tricky.

First of all We're going to create a global InfoWindow that we will reuse for all markers. This needs to be created outside of the loop. So just above the loop in the code we insert:

var infoWindow = new google.maps.InfoWindow();

This gives us an empty InfoWindow object that we can use on the map.

The next step is to attach a click event to each marker. In the code that executes we will fill the InfoWindow with the correct information and open it att the right location, pointing at the clicked marker.

At first glance it seems that you can do this the same way that you add markers:

// Attaching a click event to the current marker
google.maps.event.addListener(marker, "click", function(e) {
  infoWindow.setContent(data.description);
  infoWindow.open(map, marker);
});

The problem with this approach is that when you're trying to add more than one InfoWindow, they will all have the same content as the one in the last iteration. To prevent this from happening we need to use something called a closure.

Closures

What a closure does is to persist the data in each iteration of the loop so that it's bound to that particular marker.

One way of doing this is by encapsulating the code inside an anonymous function that is instantly executed. You need to make sure to pass the information from the current iteration to the anonymous function. In our case we're going to pass the current marker and the current data.

This is kind of a confusing concept and a bit hard to explain, so lets instead look at some code.

Implementing the closure

// Creating a closure to retain the correct data
//Note how I pass the current data in the loop into the closure (marker, data)
(function(marker, data) {

  // Attaching a click event to the current marker
  google.maps.event.addListener(marker, "click", function(e) {
    infoWindow.setContent(data.description);
    infoWindow.open(map, marker);
  });

})(marker, data);

By passing the data to the anonymous function we make sure that it will stay there. We're essentially creating 3 self contained objects (closures) from our 3 locations.

Now if we're try the code, it will work perfectly and each InfoWindow will display the right information.

Tip: Nicholas Johnson explains how closures work in 5 easy bullet points in his short post, What is it with Closure?

Live Demo

Conclusion

I hope that this example will clear out some confusion on this topic. Closures are a pretty confusing concept but once you understand how it works, it's something you we'll easily be able to apply in your own code. Anyway, you should be able to grab the code from this example and use it as a boilerplate to tweak your own needs.

Happy Coding!

My Google Maps book

If you found this article useful you might be interested in my book Beginning Google Maps API 3. It covers everything you need to know to create awesome maps on your web sites. Buy it on Amazon.com

About the author

Gabriel Svennerberg is an independent Interaction/UI Designer and Web Developer living in Sweden. When he's not busy building web application designed for humans, he writes about all things web on his site In usability we trust. Gabriel is the author of the book Beginning Google Maps API 3 published by Apress.
  • Corey Bell

    The closure does not work for me. I see three markers but only Copenhagen displays an infoWindow. Can you please post the entire code as one page?

    • http://www.svennerberg.com Gabriel Svennerberg

      You can always check out the code in the Live Demo. Here’s a direct link to the js file.

      Cheers!

      • Corey Bell

        Thank you! I got it to work, I think I had the order mixed up.

  • http://www.facebook.com/reza.esa1 Reza Esa

    I’m copy your knowledge.
    thanks for info.
    this very helping for me.
    thanks a lot. :)

  • Seamus Campbell

    Hi – I’m working through your book (which is great btw), and trying to use the above example. However my base code is ColdFusion. I have a query from my database which I can convert to a JSON object with serializeJSON. However my format is very different from your example and I can’t see how to loop over the json object I have.
    Is there a quick way you can see that I can read it or is there another way I should go.
    My json looks like this:
    {“COLUMNS”:["BUSINESS_NAME","LATITUDE","LONGITUDE"],”DATA”:[["sdfdsf Books",-36.890408,121.154751],["dsdsdsd Booksellers",-14.921735,18.602189],["fff ints",-17.8451823,195.0541819]]}
    Any help gratefully accepted

  • Mike Zin

    Thanks for the elaboration/clarification. I bought your book last year and highly recommend it!

    • http://www.svennerberg.com Gabriel Svennerberg

      That’s nice to hear. Thanks for the recommendation!

  • http://twitter.com/riemino riemino

    Thank you! The closure portion was all that I was missing for my feature to work. :)

  • Batowiise

    I bought your book. I want to know how to implement this same feature to read a json file instead of what is currently there. Regards.

  • Pippo_mares

    that’s the SOLUTION !!!
    thanks

  • Pippo mares

    but what if I want one info window open on page load?
    I have tried to make a infoWindow on page load and it works, but when I click on the markers in the json data:
    a) infoWindow at page load stays open
    b) once closed it will not display again (that’ maybe because it only display on pageload)
    how can I solve this?