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)
Without actually testing I would say that what's missing is removing possible existing marker cluster layer when creating a new one.
So probably the code should be something like:
const makeFoo = async (bounds) => {
// get points for `bounds` from the server
const url = `server/?bounds`;
const response = await fetch(url);
if (response.ok) {
if (LAYERS.foo && map.hasLayer(LAYERS.foo)) {
map.removeLayer(LAYERS.foo);
}
LAYERS.foo = L.markerClusterGroup();
const records = await response.json();
records.forEach((r) => LAYERS.foo.addLayer(L.marker(new L.LatLng(r.lat, r.lng)));
map.addLayer(LAYERS.foo);
}
}
Best Answer
I recommend putting all markers into a layerGroup or a featureGroup, such as:
Then you add the markers to the group:
Then you can easily remove the markers from the map by using the removeLayer method on that group.
For example, if you want to remove the marker with the ID 219, then you would have to do the following: