Reputation: 58999
Is there any way to get notification when an element is removed from the DOM, either directly or as part of a subtree? It seems like the only methods available are just for directly removed nodes, but I would like to get a notification when a whole subtree that contains my node is removed.
EDIT
Seems the problem wasn't entirely clear, so I have made a challenge: https://jsbin.com/winukaf
The DOM looks like this:
<body>
<div class="root">
<div class="great-grand-parent">
<div class="grand-parent">
<div class="parent">
<div class="leaf">
Am I still here?
</div>
</div>
</div>
</div>
</div>
</body>
and the challenge is to notify when any one of the elements here are removed, since that will remove the leaf node from the DOM tree.
Upvotes: 15
Views: 12782
Reputation: 46353
Here is a ready-to-use snippet that works (I modified this answer to make it simpler, a few things were unnecessary, and I added more removal cases), using the MutationObserver
HTML5 API.
var obs = new MutationObserver(mut => console.log(mut[0].removedNodes[0].id));
obs.observe(document.getElementById('root'), { childList: true, subtree: true });
setTimeout(() => { document.getElementById('leaf').remove(); }, 2000);
setTimeout(() => { document.getElementById('grand-parent').remove(); }, 4000);
setTimeout(() => { document.getElementById('great-grand-parent').outerHTML = '<div id="new-born">Hello!</div>'; }, 6000);
setTimeout(() => { document.getElementById('new-born').remove(); }, 8000);
<div id="root">
<div id="great-grand-parent">
<div id="grand-parent">
<div id="parent">
Parent
<div id="leaf">
Am I still here?
</div>
</div>
</div>
</div>
</div>
Upvotes: 2
Reputation: 2573
There's a HTML5 API called MutationObserver and it has pretty good support
Here's an example:
// Element is the whatever subtree/element you need to watch over
var in_dom = document.body.contains(element);
var observer = new MutationObserver(function(mutations) {
if (document.body.contains(element)) {
if (!in_dom) {
console.log("element inserted");
}
in_dom = true;
} else if (in_dom) {
in_dom = false;
console.log("element removed");
}
});
observer.observe(document.body, {childList: true, subtree: true});
Upvotes: 15
Reputation: 6707
You should use the MutationObserver API to accomplish this. Here's MDN's example adapted to a simple scenario:
// Select the node that will be observed for mutations
var targetNode = document.getElementsByClassName('root')[0];
// Options for the observer (which mutations to observe)
var config = {
childList: true,
subtree: true
};
// Callback function to execute when mutations are observed
var callback = function(mutationsList, observer) {
console.log('A child node has been added or removed.');
console.log(mutationsList[0]);
};
// Create an observer instance linked to the callback function
var observer = new MutationObserver(callback);
// Start observing the target node for configured mutations
observer.observe(targetNode, config);
var subElement = document.getElementsByClassName('parent')[0];
var elementToRemove = document.getElementsByClassName('leaf')[0];
var anotherElement = document.getElementsByClassName('great-grand-parent')[0];
setTimeout(function() {
subElement.removeChild(elementToRemove);
}, 500);
setTimeout(function() {
targetNode.removeChild(anotherElement);
}, 500);
// Later, you can stop observing
// observer.disconnect();
<div class="root">
<div class="great-grand-parent">
<div class="grand-parent">
<div class="parent">
<div class="leaf">
Am I still here?
</div>
</div>
</div>
</div>
</div>
Upvotes: 0