Reputation: 6525
NOTE: I'm using v3 of the Google Maps API
I'm trying to add an info window to each marker I put on the map. Currently I'm doing this with the following code:
for (var i in tracks[racer_id].data.points) {
values = tracks[racer_id].data.points[i];
point = new google.maps.LatLng(values.lat, values.lng);
if (values.qst) {
var marker = new google.maps.Marker({map: map, position: point, clickable: true});
tracks[racer_id].markers[i] = marker;
var info = new google.maps.InfoWindow({
content: '<b>Speed:</b> ' + values.inst + ' knots'
});
tracks[racer_id].info[i] = info;
google.maps.event.addListener(marker, 'click', function() {
info.open(map, marker);
});
}
track_coordinates.push(point);
bd.extend(point);
}
The problem is when I click on a marker it just displays the info window for the last marker added. Also just to be clear the info window appears next to the last marker not the marker clicked on. I'd imagine my problem is in the addListener portion but am not postitive. Any ideas?
Upvotes: 48
Views: 106255
Reputation: 136
In My case (Using Javascript insidde Razor) This worked perfectly inside an Foreach loop
google.maps.event.addListener(marker, 'click', function() {
marker.info.open(map, this);
});
Upvotes: 1
Reputation: 1592
You can use this
in event:
google.maps.event.addListener(marker, 'click', function() {
// this = marker
var marker_map = this.getMap();
this.info.open(marker_map);
// this.info.open(marker_map, this);
// Note: If you call open() without passing a marker, the InfoWindow will use the position specified upon construction through the InfoWindowOptions object literal.
});
Upvotes: 36
Reputation: 67
I had a similar problem. If all you want is for some info to be displayed when you hover over a marker, instead of clicking it, then I found that a good alternative to using an info Window was to set a title on the marker. That way whenever you hover the mouse over the marker the title displays like an ALT tag. 'marker.setTitle('Marker '+id);' It removes the need to create a listener for the marker too
Upvotes: 0
Reputation: 971
The only way I could finally get this to work was by creating an array in JavaScript. The array elements reference the various info-windows (one info-window is created for each marker on the map). Each array element contains the unique text for its appropriate map marker. I defined the JavaScript event for each info-window based on the array element. And when the event fires, I use the "this" keyword to reference the array element to reference the appropriate value to display.
var map = new google.maps.Map(document.getElementById('map-div'), mapOptions);
zipcircle = [];
for (var zip in zipmap) {
var circleoptions = {
strokeOpacity: 0.8,
strokeWeight: 1,
fillOpacity: 0.35,
map: map,
center: zipmap[zip].center,
radius: 100
};
zipcircle[zipmap[zip].zipkey] = new google.maps.Circle(circleoptions);
zipcircle[zipmap[zip].zipkey].infowindowtext = zipmap[zip].popuptext;
zipcircle[zipmap[zip].zipkey].infowindow = new google.maps.InfoWindow();
google.maps.event.addListener(zipcircle[zipmap[zip].zipkey], 'click', function() {
this.infowindow.setContent(this.infowindowtext);
this.infowindow.open(map, this);
});
}
Upvotes: 0
Reputation: 11
for Earth plugin APIs, create the balloon outside your loop and pass your counter to the function to get unique contents for each placemark!
function createBalloon(placemark, i, event) {
var p = placemark;
var j = i;
google.earth.addEventListener(p, 'click', function (event) {
// prevent the default balloon from popping up
event.preventDefault();
var balloon = ge.createHtmlStringBalloon('');
balloon.setFeature(event.getTarget());
balloon.setContentString('iframePath#' + j);
ge.setBalloon(balloon);
});
}
Upvotes: 1
Reputation: 615
The add_marker still has a closure issue, cause it uses the marker variable outside the google.maps.event.addListener scope.
A better implementation would be:
function add_marker(racer_id, point, note) {
var marker = new google.maps.Marker({map: map, position: point, 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;
}
I also used the map from the marker, this way you don't need to pass the google map object, you probably want to use the map where the marker belongs to anyway.
Upvotes: 9
Reputation: 6525
Hey everyone. I don't know if this is the optimal solution but I figured I'd post it here to hopefully help people out in the future. Please comment if you see anything that should be changed.
My for loops is now:
for (var i in tracks[racer_id].data.points) {
values = tracks[racer_id].data.points[i];
point = new google.maps.LatLng(values.lat, values.lng);
if (values.qst) {
tracks[racer_id].markers[i] = add_marker(racer_id, point, '<b>Speed:</b> ' + values.inst + ' knots<br /><b>Invalid:</b> <input type="button" value="Yes" /> <input type="button" value="No" />');
}
track_coordinates.push(point);
bd.extend(point);
}
And add_marker
is defined as:
var info_window = new google.maps.InfoWindow({content: ''});
function add_marker(racer_id, point, note) {
var marker = new google.maps.Marker({map: map, position: point, clickable: true});
marker.note = note;
google.maps.event.addListener(marker, 'click', function() {
info_window.content = marker.note;
info_window.open(map, marker);
});
return marker;
}
You can use info_window.close() to turn off the info_window at any time. Hope this helps someone.
Upvotes: 1
Reputation: 344521
You are having a very common closure problem in the for in
loop:
Variables enclosed in a closure share the same single environment, so by the time the click
callback from the addListener
is called, the loop will have run its course and the info
variable will be left pointing to the last object, which happens to be the last InfoWindow
created.
In this case, one easy way to solve this problem would be to augment your Marker
object with the InfoWindow
:
var marker = new google.maps.Marker({map: map, position: point, clickable: true});
marker.info = new google.maps.InfoWindow({
content: '<b>Speed:</b> ' + values.inst + ' knots'
});
google.maps.event.addListener(marker, 'click', function() {
marker.info.open(map, marker);
});
This can be quite a tricky topic, if you are not familiar with how closures work. You may to check out the following Mozilla article for a brief introduction:
Also keep in mind, that the v3 API allows multiple InfoWindow
s on the map. If you intend to have just one InfoWindow
visible at the time, you should instead use a single InfoWindow
object, and then open it and change its content whenever the marker is clicked (Source).
Upvotes: 81
Reputation: 7213
Try this:
for (var i in tracks[racer_id].data.points) {
values = tracks[racer_id].data.points[i];
point = new google.maps.LatLng(values.lat, values.lng);
if (values.qst) {
var marker = new google.maps.Marker({map: map, position: point, clickable: true});
tracks[racer_id].markers[i] = marker;
var info = new google.maps.InfoWindow({
content: '<b>Speed:</b> ' + values.inst + ' knots'
});
tracks[racer_id].info[i] = info;
google.maps.event.addListener(tracks[racer_id].markers[i], 'click', function() {
tracks[racer_id].info[i].open(map, tracks[racer_id].markers[i]);
});
}
track_coordinates.push(point);
bd.extend(point);
}
Upvotes: 0