I have some hierachic structured point-layers in a GeoJSON file using jsTree (ajax) with checkboxes to add them to the map. As I have about 20.000 points structured in 2.000 nodes representing the layers I have to to it in an automated way.

My idea is to connect the jsTree id with an id in the GeoJSON, so the Node ID of the jstree corresponds with the "treeid" (node.id===treeid, both are strings) in the GeoJSON file. The string ID's are generated in a Database and exported as JSON. Each checkbox adds an ID assigned layer to a layergroup on the map. Unchecking should remove that particular layer. The user can activate as much checkboxes as he likes.

Based on this question I set the default _leaflet_id equal to the "treeid" to use it as an identifier for each Layer. This works basically.

Example of the GeoJSON:

var collection = {"type": "FeatureCollection","crs": {"type": "name","properties": {"name": "urn:ogc:def:crs:OGC:1.3:CRS84"}},   "features": [{ "type": "Feature",
   "properties": {
     "dta_1": "Node_1",
     "treeid": '01 01 002 00001'
   "geometry": {
     "type": "Point",
     "coordinates": [38.933333, 40.816667]
   "type": "Feature",
   "properties": {
     "dta_1": "Node_2",
     "treeid": '01 01 002 00002'
   "geometry": {
     "type": "Point",
     "coordinates": [38.9551, 40.7626]

Example of the jsTree (simple JSON):

$('#data').jstree({'core': {'data': [{
     "id": "01",
     "parent": "#",
     "text": "Root"
   }, {
     "id": "01 01 002 00001",
     "parent": "01",
     "text": "Node_1"
   }, {
     "id": "01 01 002 00002",
     "parent": "01",
     "text": "Node_2"
   } ...

My checkbox code:

var group = {}; 
var layergroup =  L.layerGroup().addTo(map);
$('#data').on("check_node.jstree", function(e, data) {
            group =  L.geoJson(collection, {    
            onEachFeature: function(feature, layer) {
                           layer._leaflet_id = data.node.id;},      
            filter: function(feature, layer) {
                    if (feature.properties.treeid==data.node.id) return true}});
            group.treeid = data.node.id
 /*         layergroup.eachLayer(function(layer){
            layer._leaflet_id = data.node.id;
            }) */
.on("uncheck_node.jstree", function(e, data){
if (e._layers[data.node.id]) layergroup.removeLayer(e);})});
//   if (layer._leaflet_id === data.node.id) {
//   layergroup.removeLayer(layer)}

A working fiddle is here: jsfiddle

Using the "onEachFeature" Function works fine for one point, it is removed correctly. So I thought, it works, but as you can see in the fiddle, if there are many points (Node_2) again only one point (the first one) is added to the map. (Because only the first one is assigned?)

Using the "eachLayer" method adds all points as expected, but of course the uncheck code doesn't work. Changing to the outcommented code does not work.

Where is the point I'm missing on the "onEachfeature" Function to add all points with the same treeid?

Or the other option: How to change the uncheck code?

I need to add all points with the same id referencing a specific node.id to a layergroup by a checkbox, unchecking it should remove them from the layergroup and the map.

  • I looked at jsfiddle but was not able to understand what is not working correctly. Can you add to you question the exact behaviour that is needed (and is not happening), for example: if I select /unselect Root this should happen, if I select/unselect Node_1 this should happen, if I select/unselect child node this should happen ...
    – TomazicM
    Commented Jun 25, 2019 at 18:35
  • Thank you for your comment. As I wrote above, using onEachFeature adds only the first point of the GeoJson to the map, but if you look at the GeoJson, "Node_2" has four points with the same id. Those four points are added If I use 'layergroup,eachLayer' instead, but in that case the uncheck code has no effect. I think, this is a problem of correct referencing the layers. When I use the real data, only one point out of eg. 1000 is added to the map.So, if I check "Node_2, four points should be on the map, and removed, not just one
    – McOS
    Commented Jun 25, 2019 at 19:07
  • In your decription you mixed desired behaviour and implementation in Leaflet, so I still don't understand without going through the code. So please just simple desired behaviour (and not as comment but edit the question).
    – TomazicM
    Commented Jun 25, 2019 at 19:15
  • thanks, I edited the question
    – McOS
    Commented Jun 25, 2019 at 19:24

1 Answer 1


I don't quite understand the intended logic of jsfiddle code, but there is definitely no need to load GeoJSON on each tree node selection/click, it can be loaded once at the beginning and then it's features iterated through when neccessary.

The other thing is that you should never modify internal Leaflet _leaflet_id property. You can only read it with getLayerId method of group layer and later use it to get desired layer with getLayer method.

In the code below (only relevant part from jsfiddle) GeoJSON features are loaded only once into featureLayer group layer, which is not added to map. Then upon tree node selection/unselecton features in featureLayer are iterated through and layer with id property that corresponds to tree node id is added/removed to layergroup layer:

var featureLayer = L.geoJson(collection);

  .on("check_node.jstree", function(e, data) {
    featureLayer.eachLayer(function (layer) {
      if (layer.feature.properties.treeid == data.node.id) {

  .on("uncheck_node.jstree", function(e, data) {
      if (layer.feature.properties.treeid == data.node.id) {

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.