[GIS] Add/Remove markers

angularjsleaflet

I'm trying to add/remove markers to a leaflet map. I have 6 checkboxes, what i want is that when I check any of them show the points in the map, and when uncheck one of them the only to remove is the one I uncheck.

What I have,

The checkboxes:

.row
    .col-md-12
        .row
            label.col-md-7 First check
            input.col-md-1(type="checkbox" ng-model="locations.somecheck1")
        .row
            label.col-md-7 Second check
            input.col-md-1(type="checkbox" ng-model="locations.somecheck2")
        .row
            label.col-md-7 Third check
            input.col-md-1(type="checkbox" ng-model="locations.somecheck3")
        .row
            label.col-md-7 Fourth check
            input.col-md-1(type="checkbox" ng-model="locations.somecheck4")
        .row
            label.col-md-7 Five check
            input.col-md-1(type="checkbox" ng-model="locations.somecheck5")
        .row
            label.col-md-7 Six check
            input.col-md-1(type="checkbox" ng-model="locations.somecheck6")

The controller:

$scope.$watch('locations.somecheck1', function(somecheck1) {

      if ($scope.locations.somecheck1 === true) {
        findItem.find(function(err, items) {

          lastLocationItems = items[0].items;
          items = lastLocationItems.map((item) => GeoService.toGeoJSON(item, { idKey: '_id', geometryKey: 'lastLocation'}));
          getEpc(items, ssccIcon);
        });
      } else {
        leafletData.getMap().then(function(map) {

          map.removeLayer(objetosLayer);
        });
      }
    }, true);

The function that create the layer:

function getEpc(items, icon) {
      var objectsLayer = L.geoJson(items, {
        pointToLayer: function(items, latlng) {
          var result;

          if (icon !== undefined) {
            result = L.marker(latlng, {
              icon: icon
            });
          } else {
            result = L.marker(latlng);
          }

          return result;
        }
      });

      leafletData.getMap().then(function(map) {

        objectsLayer.addTo(map);
      });
    }

In the watch function, is the remove function that activates when the checkbox is false. If I check 2 checkbox, the function create both, but when I want to remove the first one, only removes the second check. I look and found that every time I click a checkbox it's create a new layer with the new info.

How can I automatically create a layer for every checkbox in the function getEpc?

Best Answer

Save a reference to your object layer(s) and then remove them before re-adding to avoid duplicates. It looks like you were already on the right track, but your current objectsLayer has a scope inside getEpc().. you need to define this at a higher level, and you need to maintain a separate layer for each checkbox.

Note that Leaflet already supports this concept out-of-box by using the Layers control. You can create overlays, add them to the layers control, and use checkboxes to automatically toggle the layers, which will add and remove them for you.

However, if you want to do it on your own, you need to do a few things:

First, modify getEPC() to return a reference to the new layer:

function getEpc(items, icon) {
  var objectsLayer = L.geoJson(items, {
    pointToLayer: function(items, latlng) {
      var result;
      if (icon !== undefined) {
        result = L.marker(latlng, {
          icon: icon
        });
      } else {
        result = L.marker(latlng);
      }
      return result;
    }
  });
  leafletData.getMap().then(function(map) {
    objectsLayer.addTo(map);
  });
  // return layer reference so we can manage it
  return objectsLayer;
}

Then, you need to manage the layers as you add and remove them.

Note: it will get very tedious to do this for each checkbox.. you may want to use a watchGroup or watchCollection instead. But to keep the example simple, I tried to use your code without making major modifications:

// global cache for overlays. 
// you may want to put this somewhere better, but keeping example simple..
var overlays = {};

$scope.$watch('locations.somecheck1', function(somecheck1) {
  if ($scope.locations.somecheck1 === true) {
    findItem.find(function(err, items) {
      lastLocationItems = items[0].items;
      items = lastLocationItems.map((item) => GeoService.toGeoJSON(item, { idKey: '_id', geometryKey: 'lastLocation'}));
      var objectsLayer = getEpc(items, ssccIcon); // get new layer
      // save layer reference so it can be removed later
      overlays["somecheck1"] = objectsLayer; 
    });
  } else if(overlays["somecheck1"]) {
    leafletData.getMap().then(function(map) {
      map.removeLayer(overlays["somecheck1"]); // remove cached layer
    });
  }
}, true);

$scope.$watch('locations.somecheck2', function(somecheck1) {
  if ($scope.locations.somecheck2 === true) {
    findItem.find(function(err, items) {
      lastLocationItems = items[0].items;
      items = lastLocationItems.map((item) => GeoService.toGeoJSON(item, { idKey: '_id', geometryKey: 'lastLocation'}));
      var objectsLayer = getEpc(items, ssccIcon); // get new layer
      // save layer reference so it can be removed later
      overlays["somecheck2"] = objectsLayer; 
    });
  } else if(overlays["somecheck2"]) {
    leafletData.getMap().then(function(map) {
      map.removeLayer(overlays["somecheck2"]);
    });
  }
}, true);

// etc, for each checkbox (but prefer to refactor into smaller, reusable methods)