5

I have a Leaflet map that I am populating with CircleMarkers. I would like to include an additional value (a database ID) with each circle so that when I click on the circle, I can get the value and navigate somewhere else.

I would like to add the value directly to the marker and use a callback function on the entire featureGroup instead of adding a callback function to each marker, since we're dealing with over 500 markers and it would be a performance drag.

Worth mentioning: I'm using Typescript inside an Angular app, but it's still Leaflet.

What I've tried:

  var data = [
    {lat: 20.45, lng: -150.2, id: 44},
    {lat: 23.45, lng: -151.7, id: 45},
  ]
  var points = [];

  data.forEach((d) => {
    // How do I add an additional variable to this circleMarker?
    points.push(circleMarker(latLng(d.lat, d.lng), { radius: 5}));
  })

  var group = featureGroup(points);

  group.on("click", function (e) {
    console.log(e);
    // This is where I would like to get the ID number of the record
  });

2 Answers 2

9

FWIW, you have plenty ways of adding your own data to Leaflet Layers (nothing specific to Circle Markers, it is the same for Markers, but also Polygons, Polylines, etc.).

See for instance: Leaflet/Leaflet #5629 (Attach business data to layers)

In short, there are mainly 3 possible ways:

  • Just directly add some properties to the Leaflet Layer after it has been instantiated. Make sure you avoid collision with library properties and methods. You can add your own prefix to the property name to decrease the chance of collision.
var marker = L.marker(latlng);
marker.myLibTitle = 'my title';
  • Use the Layer options (usually the 2nd argument of the instantiation factory), as shown by @nikoshr. As previously, avoid collision with library option names.
L.marker(latlng, {
  myLibTitle: 'my title'
});
  • Use the Layer GeoJSON properties. Leaflet does not use those for internal purpose, so you have total freedom of this data, without any risk of collision.
L.Layer.include({
  getProps: function () {
    var feature = this.feature = this.feature || {}; // Initialize the feature, if missing.
    feature.type = 'Feature';
    feature.properties = feature.properties || {}; // Initialize the properties, if missing.
    return feature.properties;
  }
});

var marker = L.marker(latlng);

// set data
marker.getProps().myData = 'myValue';

// get data
myFeatureGroup.on('click', function (event) {
  var source = event.sourceTarget;
  console.log(source.getProps().myData);
});
4
  • Quite strange, but every time I am trying to add to marker some arbitrary property I have an error like "Property 'myLibTitle' does not exist on type 'Marker<any>'" Dou you use some extension of Leaflet? I use Leaflet 1.9.4 but I tried 1.3.1 too
    – mli
    Commented May 16 at 6:57
  • @mli seems like you are using TypeScript? If you ignore the type error (e.g. with //@ts-ignore directive), does the rest work in runtime? I am not saying you should ignore it, just to make sure. If so, please feel free to open a new question with a minimal reproducible example
    – ghybs
    Commented May 16 at 9:53
  • Yes, I'm using TypeScript (better say trying to use ;). Thanks for //@ts-ignore - it helps. But do you know how to work with ids without marking every mention of them with directive?
    – mli
    Commented May 20 at 7:12
  • @mli Please feel free to open your own question with all details.
    – ghybs
    Commented May 20 at 9:04
4
  • Events fired on members of a FeatureGroup are propagated to the FeatureGroup object
  • Event objects expose a sourceTarget member giving you access to the source marker
  • Options in a layer can be accessed as marker.options

From there, you could pass your id as a member of the options object when building your markers and retrieve this value when a marker is clicked. For example:

var points = data.map((datum) => {
    return L.circleMarker(datum, {radius: 5, id: datum.id});
});

var group = L.featureGroup(points);
group.addTo(map);

group.on("click", (e) => {
    console.log(e.sourceTarget.options.id);
});

And a demo

var data = [
	{lat: 20.45, lng: -150.2, id: 44},
	{lat: 23.45, lng: -151.7, id: 45},
]
var points = [];

var map = L.map('map', {
    center: [20.45, -150.2],
    zoom: 4
});

var points = data.map(function (datum) {
    return L.circleMarker(datum, {radius: 5, id: datum.id});
});

var group = L.featureGroup(points);
group.addTo(map);

group.on("click", function (e) {
    console.log(e.sourceTarget.options.id);
});
html, body {
  height: 100%;
  margin: 0;
}
#map {
  width: 100%;
  height: 150px;
}
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.3.1/leaflet.css"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.3.1/leaflet.js"></script>

<div id='map'></div>

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