15

I am using Leaflet in order to render a map. I created a map with markers and I don't know how to implement the Event Listener 'onClick' on each Marker.

My code

var stops = JSON.parse(json);
var map = new L.Map('map', {
  zoom: 12,
  minZoom: 12,
  center: L.latLng(41.11714, 16.87187)
});
map.addLayer(L.tileLayer('https://api.tiles.mapbox.com/v4/{id}/{z}/{x}/{y}.png?access_token={accessToken}', {
  attribution: 'Map data',
  maxZoom: 18,
  id: 'mapbox.streets',
  accessToken: '-----'
}));
var markersLayer = new L.LayerGroup();
map.addLayer(markersLayer);


//populate map from stops
for (var i in stops) {
  L.marker(L.latLng(stops[i].Position.Lat, stops[i].Position.Lon), {
    title: stops[i].Description
  }).addTo(markersLayer).bindPopup("<b>" + stops[i].Description + "</b>").openPopup();
}

Example

map.on('click', function(e) {
    alert(e.latlng);
});

Leaflet deals with event listeners by reference, so if you want to add a listener and then remove it, define it as a function:

function onClick(e) { ... }

map.on('click', onClick);
map.off('click', onClick);
1

3 Answers 3

17

Welcome to GIS Stack Exchange!

There should be no special difficulty in attaching a callback to marker(s) click event. You would simply use myMarker.on('click', callback) like you did with the map. You would also have to do that for every marker you want to attach a callback to.

Another possibility would be to add all your markers into a Feature Group (e.g. simply instantiate your markersLayer with L.featureGroup() instead of L.layerGroup()), so that you can attach the callback directly to that Group. It will receive the click events from individual markers, and you can access the individual clicked feature using event.layer.

var markersLayer = L.featureGroup().addTo(map);

// populate map from stops…

markersLayer.on("click", function (event) {
    var clickedMarker = event.layer;
    // do some stuff…
});

Demo: http://jsfiddle.net/ve2huzxw/74/

Similar question asked by someone else on Leaflet forum: https://groups.google.com/forum/#!topic/leaflet-js/RDTCHuLvMdw

1
  • Just to add, event.layer.properties will give you access to the array of all the properties (metadata) of your markers, as per GeoJSON format. So you can assign event.layer.properties.description = stops[i].Description for example.
    – Nikhil VJ
    Commented Feb 25, 2018 at 17:04
6

Modify your map population loop to assign properties to your marker.

    //populate map from stops
    for (var i in stops) {
      var oneMarker = L.marker(L.latLng(stops[i].Position.Lat, stops[i].Position.Lon), {
        title: stops[i].Description
      }).bindPopup("<b>" + stops[i].Description + "</b>").openPopup();
      
      oneMarker.properties.name = stops[i].Name;
      oneMarker.properties.description = stops[i].Description;
      oneMarker.properties.othervars = stops[i].othervars;
      oneMarker.addTo(markersLayer);
    }

Later, to access these properties (feature properties as they're called) in the onclick event,

    markersLayer.on("click", markerOnClick);

    function markerOnClick(e) {
      var attributes = e.layer.properties;
      console.log(attributes.name, attributes.desctiption, attributes.othervars);
      // do some stuff…
    }

The properties.var approach has the added benefit of making your marker be in the standard GeoJson format. Makes it compatible if, say, you need to export the data as shapefile, import markers from shapefile, etc.

3
  • 1
    I am trying to incorporated your suggestion into my own setup. But adding a simple oneMarker.properties gives me an error message "oneMarker.properties is undefined". I am overlooking something obvious?? regards btw: you misspelled properies ........properties in your example code
    – alex
    Commented May 17, 2019 at 9:12
  • 1
    ah i think i found a solution: I had to add oneMarker.properties = {}; btw: is it correct to use var oneMarker or should this be a dynamic name?
    – alex
    Commented May 17, 2019 at 9:26
  • @alex good to know about the properties hack. Yes, it's fine to use var oneMarker - it's local scope within the for loop, and the layer.addTo() line adds it value. (like: a=3; array1.push[a]; will add value 3 to the array, not a reference to a itself.)
    – Nikhil VJ
    Commented May 17, 2019 at 15:05
2

A fairly straight forward and easy way to accomplish creating an array of clickable markers within a leaflet map object is to manipulate the class list of the created marker by adding a custom incremented class name to each marker. Then it is easy to create a listener and know which marker was clicked. By skipping the active one or not, each has a retrievable click event with a reliable ID.

  // creates markers, each with a leaflet supplied class
  if (length === 1) {
    for (i = 0; i < parks.length; ++i) {
      if (parks[i].parksNumber !== parks.parksNumber)
        L.marker([parks[i].latitude, parks[i].longitude], {
          icon: parks[i].iconMarker
        }).addTo(mymap);
    }
  }

  // select all of the leaflet supplied class
  let markers = document.querySelectorAll(".leaflet-marker-icon");

  // loop through those elements and first assign the indexed custom class
  for (i = 0; i < markers.length; ++i) {
    markers[i].classList.add("marker_" + parks[i].parksNumber);

    // then add a click listener to each one
    markers[i].addEventListener("click", e => {

      // pull the class list
      let id = String(e.target.classList);

      // pull your unique ID from the list, be careful cause this list could 
      // change orientation,  if so loop through and find it
      let parksNumber = id.split(" ");
      parksNumber = parksNumber[parksNumber.length - 1].replace("marker_", "");

      // you have your unique identifier to then do what you want with
      search_Number_input.value = parksNumber;
      HandleSearch();
    });
  }

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.