I am doing a small HTML5 project with Google Maps JavaScript API v3 using JavaScript, CSS and HTML.
In this small app, my objective is to add markers to the map, and once each marker is clicked, to show some information about the marker.
My first approach was the following:
var markersArray = [];
// Adds a marker to the map and push to the array.
function addMarker(location) {
var marker = new google.maps.Marker({
position: location,
map: map,
draggable: true,
animation: google.maps.Animation.DROP,
label: markersArray.length + "",
title: markersArray.length + ""
});
markersArray.push(marker);
marker.addListener('click', function() {
clickMarkerEvent(markersArray.length - 1);
});
}
//listener
function clickMarkerEvent(index) {
alert(markersArray[index].getTitle());
}
However, When I click the marker, I only get information about the last marker placed on the map. The Listener is failing.
I tried correcting this by using scopes in JavaScript, and I even gave a look at binding, however, none of those worked.
In the end, I came up with something completely different:
var markersArray = [];
var lastMarkerClicked;
function addMarker(location) {
var marker = new google.maps.Marker({
position: location,
map: map,
draggable: true,
animation: google.maps.Animation.DROP,
label: markersArray.length + "",
title: markersArray.length + ""
});
markersArray.push(marker);
marker.addListener('click', function() {
clickMarkerEvent();
});
}
//listener
function clickMarkerEvent() {
lastMarkerClicked = event.target || event.srcElement;
alert(markersArray[lastMarkerClicked].title);
}
The problem with this last approach (even though it works) is the following:
- I am accessing the HTML element, and not the JavaScript element itself
- I am forced to using the HTML's
title
attribute to keep track of the index, which can only be done if the Marker's title is the index (cannot be anything else) - I cannot use the methods described here (https://developers.google.com/android/reference/com/google/android/gms/maps/model/Marker#public-method-summary) unless I do something like
markersArray[lastMarkerClicked.title]
, which refers back to the last point
Overall my solution works, but I truly dislike it. Is there a better way to do this?
Following is my code, I am open to suggestions !
'use strict'
/*
Best practices: For the best user experience, only one info window should be
open on the map at any one time. Multiple info windows make the map appear
cluttered. If you only need one info window at a time, you can create just
one InfoWindow object and open it at different locations or markers upon map
events, such as user clicks. If you do need more than one info window, you
can display multiple InfoWindow objects at the same time.
*/
var infowindow;
var contentString;
var lastMarkerClicked;
var markersArray = [];
var map;
// Initializes the map with a marker
function initMap() {
var myLatLng = {
lat: -25.363,
lng: 131.044
};
map = new google.maps.Map(document.getElementById('map'), {
zoom: 4,
center: myLatLng
});
// This event listener calls addMarker() when the map is clicked.
google.maps.event.addListener(map, 'click', function(event) {
addMarker(event.latLng);
});
addMarker(myLatLng);
}
// Adds a marker to the map and push to the array.
function addMarker(location) {
var marker = new google.maps.Marker({
position: location,
map: map,
draggable: true,
animation: google.maps.Animation.DROP,
label: markersArray.length + "",
title: markersArray.length + ""
});
markersArray.push(marker);
marker.addListener('click', function() {
clickMarkerEvent();
});
}
// Sets the map on all markers in the array.
function setMapOnAll(map) {
for (var i = 0; i < markersArray.length; i++) {
setMapOnMarker(i, map);
}
}
// Removes the markers from the map, but keeps them in the array.
function clearMarkers() {
setMapOnAll(null);
}
// Shows any markers currently in the array.
function showMarkers() {
setMapOnAll(map);
}
function setMapOnMarker(markerIndex, map) {
markersArray[markerIndex].setMap(map);
}
function hideMarker(markerIndex) {
setMapOnMarker(markerIndex, null);
}
function deleteMarker(markerIndex) {
hideMarker(markerIndex);
markersArray[markerIndex] = null;
}
/*
Deletes all markers in the array by removing references to them.
Note that the above method does not delete the marker. It simply removes the
marker from the map. If instead you wish to delete the marker, you should remove
it from the map, and then set the marker itself to null.
https://developers.google.com/maps/documentation/javascript/markers#remove
*/
function deleteMarkers() {
clearMarkers();
for (var i = 0; i < markersArray.length; i++) {
markersArray[i] = null;
}
markersArray = [];
}
//listeners
function clickMarkerEvent() {
lastMarkerClicked = event.target || event.srcElement;
if (markersArray[lastMarkerClicked.title].getAnimation() !== null) {
markersArray[lastMarkerClicked.title].setAnimation(null);
}
else {
markersArray[lastMarkerClicked.title].setAnimation(google.maps.Animation.BOUNCE);
}
contentString = '<div id="content">' +
'<div id="siteNotice">' +
'</div>' +
'<h1 id="firstHeading" class="firstHeading">Marker Info</h1>' +
'<div id="bodyContent">' +
'<b>Locatoin:</b> <p>' + markersArray[lastMarkerClicked.title].getPosition() + '</p>' +
'<b>Title: </b> <p>' + lastMarkerClicked.title + '</p>' +
'<button onclick="hideMarkerClickEvent()">Hide Marker</button>' +
'<button onclick="deleteMarkerClickEvent()">Delete Marker</button>' +
'</div>' +
'</div>';
if(infowindow !== null && typeof infowindow !== 'undefined')
infowindow.close();
infowindow = new google.maps.InfoWindow({
content: contentString,
maxWidth: 200
});
infowindow.open(map, markersArray[lastMarkerClicked.title]);
}
function deleteMarkerClickEvent() {
deleteMarker(lastMarkerClicked.title);
}
function hideMarkerClickEvent() {
hideMarker(lastMarkerClicked.title);
}
html,
body {
height: 100%;
margin: 0;
padding: 0;
}
#map {
height: 100%;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no">
<meta charset="utf-8">
<title>Simple markers</title>
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
<div id="map"></div>
<script type="text/javascript" src="markers.js"></script>
<script async defer src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCGj-Dsa4PtrJiyATE_upQgOkfEkjFXqoQ&callback=initMap">
</script>
</body>
</html>