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 onc
Your first approach was almost ok, the problem was that at the point when click listener was called, all markers were already in markersArray
so markersArray.length - 1
always pointed to the last marker. Just create a variable which value holds the id of the marker inside the scope of the addMarker
function. Here is the working code (notice the use of var index = markersArray.length;
):
'use strict'
var infowindow;
var contentString;
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 index = markersArray.length;
var marker = new google.maps.Marker({
position: location,
map: map,
draggable: true,
animation: google.maps.Animation.DROP,
label: index + "",
title: index + ""
});
markersArray.push(marker);
marker.addListener('click', function() {
clickMarkerEvent(index);
});
}
// 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;
}
function deleteMarkers() {
clearMarkers();
for (var i = 0; i < markersArray.length; i++) {
markersArray[i] = null;
}
markersArray = [];
}
//listeners
function clickMarkerEvent(index) {
if (markersArray[index].getAnimation() !== null) {
markersArray[index].setAnimation(null);
}
else {
markersArray[index].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[index].getPosition() + '</p>' +
'<b>Title: </b> <p>' + markersArray[index].getTitle() + '</p>' +
'<button onclick="hideMarkerClickEvent(' + index + ')">Hide Marker</button>' +
'<button onclick="deleteMarkerClickEvent(' + index + ')">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[index]);
}
function deleteMarkerClickEvent(index) {
deleteMarker(index);
}
function hideMarkerClickEvent(index) {
hideMarker(index);
}
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>
I have finally found a solution which I like (different from the one I accepted).
After a lot of research, I found this website: https://www.toptal.com/javascript/interview-questions
And I read question number 10:
In what order will the numbers 1-4 be logged to the console when the code below is executed? Why?
(function() { console.log(1); setTimeout(function(){console.log(2)}, 1000); setTimeout(function(){console.log(3)}, 0); console.log(4); })();
If you want to know the answer, feel free to read the original source.
After reading this, I came up with my version using scopes:
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: "Marker Number " + markersArray.length
});
markersArray.push(marker);
marker.addListener('click', (function(index) {
return function() {
clickMarkerEvent(index);
};
})(markersArray.length - 1));
}
//listeners
function clickMarkerEvent(index) {
alert(index);
}
This is what I was trying to do in the first place, but I have forgotten a few details.
Still, I have decided to accept the other question for its simplicity.
Here is my complete project. I added some more features like custom controls for the markers. It is not perfect, by all means, but I think it is a nice starter point for anyone interested.
'use strict'
/*global google*/
/*
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: "Marker Number " + markersArray.length
});
markersArray.push(marker);
marker.addListener('click', (function(index) {
return function() {
clickMarkerEvent(index);
};
})(markersArray.length - 1));
}
// Sets the map on all markers in the array.
function setMapOnAll(map) {
for (var i = 0; i < markersArray.length; i++) {
if(markersArray[i] !== null)
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);
}
/*
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++) {
if(markersArray[i] !== null)
markersArray[i] = null;
}
markersArray = [];
}
// Sets a marker with the given map
function setMapOnMarker(markerIndex, map) {
markersArray[markerIndex].setMap(map);
}
// Hides a single marker
function hideMarker(markerIndex) {
setMapOnMarker(markerIndex, null);
}
// Deletes a marker. Hides it first.
function deleteMarker(markerIndex) {
hideMarker(markerIndex);
markersArray[markerIndex] = null;
}
//listeners
function clickMarkerEvent(index) {
lastMarkerClicked = markersArray[index];
if (lastMarkerClicked.getAnimation() !== null)
lastMarkerClicked.setAnimation(null);
else
lastMarkerClicked.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>' + lastMarkerClicked.getPosition() + '</p>' +
'<b>Title: </b> <p>' + lastMarkerClicked.getTitle() + '</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, lastMarkerClicked);
}
function deleteMarkerClickEvent() {
deleteMarker(markersArray.indexOf(lastMarkerClicked));
}
function hideMarkerClickEvent() {
hideMarker(markersArray.indexOf(lastMarkerClicked));
}
html,
body {
height: 100%;
margin: 0;
padding: 0;
}
#map {
height: 100%;
}
#floating-panel {
position: absolute;
top: 10px;
left: 25%;
z-index: 5;
background-color: #fff;
padding: 5px;
border: 1px solid #999;
text-align: center;
font-family: 'Roboto', 'sans-serif';
line-height: 30px;
padding-left: 10px;
}
<!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="floating-panel">
<input onclick="clearMarkers();" type=button value="Hide Markers">
<input onclick="showMarkers();" type=button value="Show All Markers">
<input onclick="deleteMarkers();" type=button value="Delete Markers">
</div>
<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>