3
votes

I am trying to draw country shapes on a leaflet map using L.GeoJSON(data).addTo(map). I then want to bind a popup to the click event of that country shape...

new L.GeoJSON(data, {
  onEachFeature: function(feature, layer) {
    layer['on']('click', popupFunction);
  }
}).addTo(this.map);


popupFunction = function(event) {
  var layer = event.target;

  // Open the 'add' popup and get our content node
  var bound = layer.bindPopup(
    "<div>Hello World!</div>"
  ).openPopup();

  // Ugly hack to get the HTML content node for the popup
  // because I need to do things with it
  var contentNode = $(bound['_popup']['_contentNode']);
}

Now this works fine when the data is a single polygon, because then the layer attribute passed to the onEachFeature function is just that: a layer.

However if the data is a multipolygon (i.e. the US) this stops working because the "layer" is now a layerGroup (it has a _layers) attribute and therefore has no _popup attribute and so I can't get the _contentNode for the popup.

It seems like this should be quite a common thing, wanting a popup on a layerGroup. Why does it have no _popup attribute?

4

4 Answers

3
votes

short answer: layergroup does not support popup

plan B:

you should consider using FeatureGroup, it extends LayerGroup and has the bindPopup method and this is an example

L.featureGroup([marker1, marker2, polyline])
    .bindPopup('Hello world!')
    .on('click', function() { alert('Clicked on a group!'); })
    .addTo(map);
1
votes

First of all, you should be able to bind popUp in similar way to Using GeoJSON with Leaflet tutorial. Something like this:

var geoJsonLayer = L.geoJson(data, {
  onEachFeature: function(feature, layer) {
    layer.bindPopup('<div>Hello World!</div>');
  }
}).addTo(map);

How to further process your popUps depends on your usecase. Maybe this can be enough for you:

geoJsonLayer.eachLayer(function(layer) {
  var popUp = layer._popup;
  // process popUp, maybe with popUp.setContent("something");
});

Hope this helps..

0
votes

You cannot bind a L.Popup to anything else than a L.Layer because the popup will some coordinates to anchor on.

For a L.Marker it will be the position (L.Latlng), for the L.Polygon it will be the center (look at the code to see how it is calculated).

As for the other cases (like yours), you can open a popup but you will have to decide where the popup opens:

var popup = L.popup()
    .setLatLng(latlng)
    .setContent('<p>Hello world!<br />This is a nice popup.</p>')
    .openOn(map);
0
votes

I used this code to open all popups in a layer group:

markers.eachLayer(marker => marker.openPopup());

While dealing with layer groups, you might want to consider passing { autoClose: false, closeOnClick: false } options while binding popup, so popups won't get closed while opening new popup, or if user clicks on the map:

marker.bindPopup(item.name, { autoClose: false, closeOnClick: false });