Edited at

GoogleMapsAPIで複数のマーカーにInfoWindowを表示する

More than 3 years have passed since last update.

GoogleMapsAPIで複数のマーカーにそれぞれ吹き出しのようなInfoWindowを表示させる際にはまったのでメモ。


正解

<div id="map"></div>

<script type="text/javascript">

var markers = [{name:'Tokyo', lat:35.681382, lng:139.76608399999998},
{name:'Shibuya', lat:35.6581823, lng:139.702043},
{name:'Ueno', lat:35.7121365, lng:139.77624709999998},
{name:'Ikebukuro', lat:35.7298477, lng:139.71192859999996}];

var map;
function initMap() {
map = new google.maps.Map(document.getElementById('map'), {
center: {lat:35.681382, lng:139.76608399999998},
zoom: 13
});

markers.forEach(function (val, index, arr) {
var marker = new google.maps.Marker({
position: {lat:val.lat, lng:val.lng},
map: map
});
google.maps.event.addListener(marker, 'click', function (event) {
new google.maps.InfoWindow({
content: '<p>' + val.name + '</p>'
}).open(marker.getMap(), marker);
});
}
}

</script>
<script async defer
src="https://maps.googleapis.com/maps/api/js?callback=initMap">
</script>


間違い

はまった内容は、以下のコードでどのマーカーをクリックしてもforループの最後のマーカーのクリックイベントだけが実行されるということ。(この場合どれをクリックしても「Ikebukuro」が表示される。)

<div id="map"></div>

<script type="text/javascript">

var markers = [{name:'Tokyo', lat:35.681382, lng:139.76608399999998},
{name:'Shibuya', lat:35.6581823, lng:139.702043},
{name:'Ueno', lat:35.7121365, lng:139.77624709999998},
{name:'Ikebukuro', lat:35.7298477, lng:139.71192859999996}];

var map;
function initMap() {
map = new google.maps.Map(document.getElementById('map'), {
center: {lat:35.681382, lng:139.76608399999998},
zoom: 13
});

for (var i = 0; i < markers.length; i++) {
var val = markers[i];
var marker = new google.maps.Marker({
position: {lat:val.lat, lng:val.lng},
map: map
});
google.maps.event.addListener(marker, 'click', function (event) {
new google.maps.InfoWindow({
content: '<p>' + val.name + '</p>'
}).open(marker.getMap(), marker);
});
}
}

</script>
<script async defer
src="https://maps.googleapis.com/maps/api/js?callback=initMap">
</script>

調べて見るとほとんどのサンプルはクリックイベントをイベントリスナーに追加する処理を別functionで定義していた。自分の場合、イベント追加は最初の処理でしか使わなかったため、functionを定義してもその後は出番もなく、面倒だったので今回のforEachを採用。

原因としては、forEachを使えばうまくいっていることから、forループのところがnon thread safeだったため。