I use several maps at a time. They can be created and deleted dynamically. But when I destroy a map using map.remove() there is a memory leak and "Detached DOM trees" appears in Chrome Dev Tools.
Working example here http://84.53.192.170/patyi/index.html
How to destroy maps properly?
Remove map:
map.remove();
var node = document.getElementById("map-div-id");
node.parentNode.removeChild(node);
Create new map div:
var div = document.createElement("div");
div.setAttribute("id", "map-div-id");
// as an example add it to the body
document.body.appendChild(div);
@Starefossen DOM elements don't have remove method, you need to do node.parentNode.removeChild(node).
Not sure why there's a leak currently though. I'll look into it.
That's odd, I tried it out in this jsfiddle and getElementById().remove() works in Safari, Chrome, and Firefox.
@Starefossen it's a relatively new API, and it's not supported in IE. https://developer.mozilla.org/en-US/docs/Web/API/ChildNode.remove
Thanks for the clarification, I did not know that.
OK, seeing the issue — this happens when layers and controls that were previously added to a map continue to reference detached DOM elements even if the map itself is destroyed.
First, map.remove() should remove all layers. If not, these layers keep a dangling reference to this._map and cannot be added to any other map instance afterwards.
Second, I've found a non-completely-clean way of triggering map.remove() when the map container is removed from the DOM (#3514). See https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver , which seems to be the only way to do it.
@IvanSanchez lets not use mutation observers since we want Leaflet to work reliably in older browsers (it's not supported in IE up to 10)
@mourner I'm surprised you still have hopes for _anything_ to work reliably on IE8 :-P
I just don't like _adding_ code that's not strongly necessary and not working everywhere. :)
Merged.
Hi there. Im also having trouble removing the map. Im using react with a bootstrap modal to render the map. see the removeMap function below. I need to manually delete the object off the class. the remove function does not destroy the map instance in my case for some reason
class NeabySpot extends React.Component {
constructor(props) {
super(props);
this.state = { showModal: false };
}
componentDidUpdate(prevProps, prevState){
if(prevProps.selectedSpot !== this.props.selectedSpot) {
const lat = this.props.selectedSpot.getIn(['gpsLocation', 'lat']);
const lng = this.props.selectedSpot.getIn(['gpsLocation', 'lng']);
this.drawMap(lat, lng)
}
}
drawMap(lat, lng) {
if (!this.map) {
this.map = L.map("map-nearby");
L.tileLayer("http://{s}.tile.osm.org/{z}/{x}/{y}.png", {
attribution: '© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
}).addTo(this.map);
this.markers = new L.FeatureGroup();
this.map.addLayer(this.markers);
}
this.map.setView([lat, lng], 3);
this.mapIcon = L.icon({
iconUrl,
iconRetinaUrl,
shadowUrl,
iconSize: [25, 41],
iconAnchor: [12, 41],
popupAnchor: [1, -34],
tooltipAnchor: [16, -28],
shadowSize: [41, 41]
});
const marker = L.marker([lat, lng], {
icon: this.mapIcon
});
this.markers.clearLayers();
this.markers.addLayer(marker);
}
removeMap() {
this.map.remove();
this.map.off();
//the remove function is not working with leaflet. issue creatd on git for now
delete this.map;
}
render() {
const showModal = this.props.showModal;
const lat = this.props.urlspot.getIn(['gpsLocation', 'lat']);
const lng = this.props.urlspot.getIn(['gpsLocation', 'lng']);
return (
<div>
<Modal show={ showModal } onHide={ this.props.close } onExiting={ () => this.removeMap() } >
<Modal.Header closeButton>
<Modal.Title style={{display: 'flex', justifyContent:'center'}}>Compare Nearby Spot</Modal.Title>
</Modal.Header>
<Modal.Body>
<div style={{ height: 300 }} id="map-nearby"></div>
</Modal.Body>
<Modal.Footer>
<div>
</div>
</Modal.Footer>
</Modal>
</div>
)
}
}
export default NearbySpot;
@foodaka can you explain what you mean when you say the remove function "does not destroy the map instance"? What is it that is not being destroyed?
Even after removal of the map by .remove(), the various events still end up calling leaflet functions and end up with errors like Cannot read property '_leaflet_pos' of undefined. So it doesn't really remove the map entirely, as it seems like the div element on which map was rendered, still holding few events without actual map object.
@jpatel3 ok, thanks for reporting. ~Could you please open a new issue with an example that reproduces this problem?~ (Update: ok, I spoke too soon, I see you opened #5774 - great!) It's not likely the problem you're seeing is related to the one discussed in this three year old issue.
Most helpful comment
Even after removal of the map by
.remove(), the various events still end up calling leaflet functions and end up with errors likeCannot read property '_leaflet_pos' of undefined. So it doesn't really remove the map entirely, as it seems like the div element on which map was rendered, still holding few events without actual map object.