Like many of you out there that use Google Maps, when v3.0 of it came out you jumped at the chance to use it! But I couldn’t get the multiple markers, multiple info windows to work, no matter what I found on Google’s site.
Searching got me to this blog:
http://www.svennerberg.com/2009/09/google-maps-api-3-infowindows
And it states this guy is writing a book on this very subject. So this should have the answer. Well bollocks it did! Stop writing your book now matey!
The Problem
When in a loop adding new markers many of you have probably done something similar:
for (var i = 0; i < markers.length; i++) {
var marker = markers[i];
var infowindow = new google.maps.InfoWindow({
content: "holding..."
});
google.maps.event.addListener(marker, 'click', function () {
infowindow.open(map, maker);
});
}
This always showed the last marker that was bound to map so the info window always appeared on the last marker. Bit of a problem really.
After reading http://www.svennerberg.com/2010/04/the-state-of-this-blog/ it showed me my mistake and the actual solution…
The Solution
for (var i = 0; i < markers.length; i++) {
var marker = markers[i];
var infowindow = new google.maps.InfoWindow({
content: "holding..."
});
google.maps.event.addListener(marker, 'click', function () {
// where I have added .html to the marker object.
infowindow.setContent(this.html);
infowindow.open(map, this);
});
}
Notice the change from marker to this. As you have all seen the event fires for each marker, but as you were calling infowindow.open(map, marker) javascript engine’s memory location thingymabob (not good with names) held the last reference to marker. But you had passed in the marker to the event, so by calling this in place of marker, you get what you are looking for.
Hope this helps someone out.
[Edit]
And to auto center your map once all your points are in:
function AutoCenter() {
// Create a new viewpoint bound
var bounds = new google.maps.LatLngBounds();
// Go through each...
$.each(markers, function (index, marker) {
bounds.extend(marker.position);
});
// Fit these bounds to the map
map.fitBounds(bounds);
}
assuming you have saved each marker in a markers array, and map is a global variable on your page.
[Edit 2]
To help someone below in the comments, I created this map to help solve someone’s issue. Hopefully it did. I really should have had a full working example at the start but I can be quite lazy sometimes :S It’s done now, so you can stop complaining



Great example! Very useful and well explained! I was wondering how to attach to the click listener a way to center the map on every marker click. I got throught a lot of forums and seems map.panTo() is difficult to set up properly. Thanks!
I have spent 2 days trying to make this work. If I run my code like “The Problem”, I always open Window 3 as described.
But when I change to “The Solution” I do not get any windows at all. What does where I have added .html to the marker object” mean?
I have searched Google for hours. There is absolutely no complete code sample anywhere on the web to create multiple markers with multiple windows. Please, please, please post your code where you created the markets.
Hi Lynn,
The “.html” is actually a dynamic property I have added to the marker object. With Javascript you can add any property at any point to an object even if it is not defined before.
example:
var marker = new google.maps.Marker({ position: myLatlng, map: map, title: teacher.Firstname + " " + teacher.Surname, html: BuildTeacher(teacher, location) });So here I am building the marker object. The last line in the constructor of it has “html” as a property, which isn’t defined in the marker object from Google. I added it as, to me, it makes more sense to have the html that will be displayed in the info window, in a property conviently named html. But I could have called it bananas as javascript allows any property to be dynamically created at any point as it is a scripting language.
Once you have created your marker object with this html property, when calling :
this should work (fingers crossed
) for you. Let me know if it doesn’t.
Genius!
Really Genius!
I was heading up to it for few hours while using ExtJs with this.
You solved my problem.
Thank You
Thanks for this, this should be part of the V3 code samples
Thank you!!!!!
Thanks for this post! It solved the exact problem I was having!!!!
Thank you, thank you, thank you. Fantastic info and solved a big headache. I agree with zMastaa. This needs to be on the main Google code page for the API examples.
Great, thanx for this
was just what I needed!
[...] seemed like a common enough scenario yet the answer could not be found. Eventually I found this post which helped point me in the right [...]
[...] 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 [...]
So I’m almost there. I had this exact problem. Changing “marker” to “this” for infowindow.open worked like a charm for making the info window pop up in the right place, but I’m still not able to get the content for that marker to show up.
I’ve got my data in an array, and I want the content of the info window to show the text held in position 4 for the location for which that marker was created. Adding infowindow.setContent(this.html) just disables all infowindows.
Here’s a sample of my code:
var sites = [
['Mount Evans', 39.58108, -105.63535, 4, 'This is Mount Evans.'],
['Irving Homestead', 40.315939, -105.440630, 2, 'This is the Irving Homestead.'],
['Badlands National Park', 43.785890, -101.90175, 1, 'This is Badlands National Park'],
['Flatirons in the Spring', 39.99948, -105.28370, 3, 'These are the Flatirons in the spring.']
];
function setMarkers(map, markers) {
var redMarker = new google.maps.MarkerImage(‘redmarker.png’,
new google.maps.Size(22,22),
new google.maps.Point(0,0),
new google.maps.Point(12,12))
for (var i = 0; i < markers.length; i++) {
var sites = markers[i];
var siteLatLng = new google.maps.LatLng(sites[1], sites[2]);
var marker = new google.maps.Marker({
position: siteLatLng,
map: map,
icon: redMarker,
title: sites[0],
zIndex: sites[3]
});
var infowindow = new google.maps.InfoWindow({
});
google.maps.event.addListener(marker, 'click', function() {
infowindow.setContent(this.html);
infowindow.open(map,this);
});
}
}
Hey Billy,
What you have forgotten to do is add the html to the marker:
for (var i = 0; i < markers.length; i++) {
var sites = markers[i];
var siteLatLng = new google.maps.LatLng(sites[1], sites[2]);
var marker = new google.maps.Marker({
position: siteLatLng,
map: map,
icon: redMarker,
title: sites[0],
zIndex: sites[3],
html: sites[4]
});
The “html” property is not part of the standard Marker object. I added it myself, which anyone can do with javascript, to make it easier to understand.
With the above change to your code, then infowindow.setContent(this.html) should now work.
Let me know if this helps,
Colin
AH! That makes perfect sense. NOW I get it.
However it’s still not working. I must have something in the wrong place in my code. If I assign content in the infowindow rather than setContent in the event listener, it works, but of course that’s not the text I need. Below is the full script using content: but not setContent:
function initialize() {
var centerMap = new google.maps.LatLng(39.828175, -98.5795);
var myOptions = {
zoom: 4,
center: centerMap,
mapTypeId: google.maps.MapTypeId.ROADMAP
}
var map = new google.maps.Map(document.getElementById(“map_canvas”), myOptions);
setMarkers(map, sites);
}
var sites = [
['Mount Evans', 39.58108, -105.63535, 4, 'This is Mount Evans.'],
['Irving Homestead', 40.315939, -105.440630, 2, 'This is the Irving Homestead.'],
['Badlands National Park', 43.785890, -101.90175, 1, 'This is Badlands National Park'],
['Flatirons in the Spring', 39.99948, -105.28370, 3, 'These are the Flatirons in the spring.']
];
function setMarkers(map, markers) {
var redMarker = new google.maps.MarkerImage(‘redmarker.png’,
new google.maps.Size(22,22),
new google.maps.Point(0,0),
new google.maps.Point(12,12))
for (var i = 0; i < markers.length; i++) {
var sites = markers[i];
var siteLatLng = new google.maps.LatLng(sites[1], sites[2]);
var marker = new google.maps.Marker({
position: siteLatLng,
map: map,
icon: redMarker,
title: sites[0],
zIndex: sites[3],
html: sites[4]
});
var contentString = '’+
”+
”+
‘Uluru’+
”+
‘Uluru, also referred to as Ayers Rock, is a large ‘ +
‘sandstone rock formation in the southern part of the ‘+
‘Northern Territory, central Australia. It lies 335 km (208 mi) ‘+
‘south west of the nearest large town, Alice Springs; 450 km ‘+
‘(280 mi) by road. Kata Tjuta and Uluru are the two major ‘+
‘features of the Uluru – Kata Tjuta National Park. Uluru is ‘+
‘sacred to the Pitjantjatjara and Yankunytjatjara, the ‘+
‘Aboriginal people of the area. It has many springs, waterholes, ‘+
‘rock caves and ancient paintings. Uluru is listed as a World ‘+
‘Heritage Site.’+
‘Attribution: Uluru, ‘+
‘http://en.wikipedia.org/w/index.php?title=Uluru (last visited June 22, 2009).’+
”+
”;
var infowindow = new google.maps.InfoWindow({
content: contentString
});
google.maps.event.addListener(marker, ‘click’, function() {
//infowindow.setContent(this.html);
infowindow.open(map,this);
});
}
}
Two things…you know the line to set the content is commented out? If you do, could you add this to that same method “alert(this.html);” and see what the alert window has in it.
Let me know how you get on.
Colin
Yes, I know it’s commented out in that bit I copied for you.
When I put an alert outside of the addListener it works. Inside, it doesn’t.
Ok not sure what you are doing wrong your side. I copied your code above, not exactly as I didn’t have the image, and I reduced the amount of text on the contentString variable.
Other than that it was the same, and worked perfectly fine. Could I ask you to double check things, flush browser cache – if the js is in an extra file things can go a bit off – and remove the comments.
You are doing it right.
Man I really don’t know what the heck is wrong if it works for you. I emptied the cache, tried Firebug and opened in a brand new browser. It will not work.
I found an interesting blog post by someone who seems to have figured out the problem, however his JS skills are beyond mine and his explanations aren’t detailed enough to help me apply this to my own code. Check this out:
http://www.aaronkjackson.com/2010/06/how-to-show-an-infowindow-for-multiple-markers-using-google-maps-v3/
Here, I have thrown a full example up on a url using your code above to show it is working properly. Not sure what you are doing wrong though as everything looks great.
http://ratemyyogateacher.co.uk/map.html
Let me know how you get on with that,
Colin
Hi, Colin, and many thanks for your post. I’ve tried a lot of ways, but yours seems the easiest and most intelligible. It helped me a lot…
Now, I am working on an implementation at http://cud.dvartora.ro and can’t seem to make it work as it should. The script is at http://cud.dvartora.ro/gmap.js . Basically, I am loading the markers from a mySQL database dynamically via XML (depending on the area of the map being shown). If the map bounds change, the script is supposed to clear the markers and load the new markers for that particular area from the database. So, the sites array needs to be dynamically generated each time the bounds of the viewport change.
For some reason, the clearing of previous markers doesn’t work properly. I get multiple markers at the same (or almost the same) location, as shown by the fact that the shadow seems to darken, and gets bigger. Just enter “Bucharest, Romania” in the search field, click “Cautare” (Search), zoom out a few times and you’ll see what I mean.
Also, in your example, the infoWindow “moved” when you clicked on another marker. In my implementation, a new infoWindow is open and the ones that are already open for other markers stay open, which is not what I want.
I am sure I am missing something. Any and all help will be greatly appreciated, as I have done all I know and I’ve been pulling my hair with this for 3 days in a row already…
Many thanks.
Give me until the weekend to look into if that’s ok. Bit tied down with work currently – well they pay my wages! But one thing I’d say just from the quick scan of your js…get yourself jQuery in there. Will help no end even with just reduceing document.getElementById(x) to $(“#x”). Speak soon.
Just quickly noticed you are doing this:
var infoWindow = new google.maps.InfoWindow({
content: infoWindowContent[number]
});
/* other code */
infowindows.clear();
infowindows.push(infoWindow);
Then you are essentially adding a new info window each time. You will notice my code uses only 1 info window, and applies the marker to it, when the marker is clicked:
for (var i = 0; i < markers.length; i++) {
var marker = markers[i];
// I really should move this outside the loop as it would be cleaner, but i got lazy!
var infowindow = new google.maps.InfoWindow({
content: “holding…”
});
google.maps.event.addListener(marker, ‘click’, function () {
// where I have added .html to the marker object.
infowindow.setContent(this.html);
infowindow.open(map, this);
});
}
The Google api then closes the current info window, applies the html, and reopens it at the new marker point.
So that’s possibly why the info windows don’t close, you are creating a new one each time, and a close event isn’t sent to the other infowindows.
Ok, good point. I was hoping that by closing all the infowindows and by emptying the infowindows array before I open a new one on marker click, that would be solved. In any case, I have the close() method in a for
for (var i=0; i < markers.length; i++) {
infowindows[i].close();
} // end for loop
infowindows.clear();
so it should work, no? Only then I do:
infowindows.push(infoWindow);
Also, in the other implementation, based on your solution (http://cud.dvartora.ro/youarenotme), where only one infowindow should be opened and "moved" from marker to marker, there are ALSO multiple infowindows open at one time. Also, there, the script generates multiple markers too, at the same location.
I'm really baffled with both implementations, each in its own way…
I think you are baffling yourself.
Here are the steps:
1. Create your map
2. Get your data for your markers
3. For each bit of data, create a marker, add it to your map
4. For each marker add the click event
5. Create a global info window variable
6. When the click happens, set the content in the infowindow, and then call the open method with the map and the marker.
That’s it. Stray from that, and you will get into bother.
What you seem to be doing is creating a bunch of markers, and then an infowindow for EACH marker and storing the infowindow in an array. You then open the associated infowindow when you click a marker. Thus the previous infowindow stays open as it doesn’t know (or really care) another info window has opened.
If you use 1 info window only, it will react properly when you call the open method again with a different marker.
So follow the steps above, and see. Any bother you can hire me to rewrite your code (am cheap, a pint and bit of dinner generally enough).
Thanks. Did you have a chance to take a look at http://cud.dvartora.ro/youarenotme yet? That is, as far as I was trying to make it, based entirely on your solution/implementation. Can you give me a hint why THAT isn’t working?
In any case, I will try to start again from scratch, following your 6 steps. Hopefully, I will be successful. If not, I’ll bother you again.
Many thanks again,
Sorin
I think it is working. I searched for “număr” and the mapped zoomed into a blank spot. But I zoomed out and there were couple of hundred points across Africa.
I click one or two and the windows open and closed as expected…on some of them. But others not.
Are you somehow adding the points more than once?
Well I have your code, and data, I might try something tonight as you now have my attention.
Finally got it to work properly. Hurray!
I rewrote the whole thing from scratch using your ideas (for which, your name will go in the comments in the JS file
).
Only thing I added was an clearOverlay() function to delete all the markers from the map on every ‘idle’ event, right before new markers are added to the map. I’m not 100% sure it’s really necessary, though. In any case, it seems the ‘idle’ event, as well as the ‘bounds_changed’ event, are firing way too quickly (because of tile loading) and sometimes markers are “doubled” on the map. Can’t do much about that, it seems…
I have the brand new implementation at http://cud.dvartora.ro/inprogress, and I’ll keep it there for a few hours (then I’ll put the working script in the root folder and continue working, cause I have some other stuff to do for this website). If you want to copy and scripts, you can do that. Or if you want me to email them to you, just let me know.
Many many thanks again. You’ve saved my sanity today…
Take care.
Glad you are happy
and I have been there with the sanity thing…hence why I wrote this post!
No thanks on the scripts side of things, and don’t worry about putting my name on things – all this is out for the world to take and play with as they please.