Search code examples
javascriptdomdom-eventsmutation-observers

Detect when a node is deleted (or removed from the DOM because a parent was)


I want to detect when a node (nodeX, say) is no longer available, either because it was deleted or because its parent (or its parents parent) was deleted.

So far, all I can think of is to use Mutation Observer to see any deletions on the page, and check if the deleted nodes was nodeX or had nodeX for a descendant.

Is there an easier way?


Please note: as far as I understand, the linked question (that this question "is a duplicate of") asks "how can I detect a [direct] deletion of a node". Mine asks "How can I detect the deletion of a node or its parent (or any other ancestor)".

As far as I understand, this is not straightforward with mutation observers: You need to check every deleted node to see if it was an ancestor.

This is what I seek to confirm or deny.

As far as I understand, that is different from the linked question.


Solution

  • Here is an implementation that identifies how the element was removed (either directly or because a parent was removed)

    var target = document.querySelector('#to-be-removed');
    
    var observer = new MutationObserver(function(mutations) {
      // check for removed target
      mutations.forEach(function(mutation) {
        var nodes = Array.from(mutation.removedNodes);
        var directMatch = nodes.indexOf(target) > -1
        var parentMatch = nodes.some(parent => parent.contains(target));
        if (directMatch) {
          console.log('node', target, 'was directly removed!');
        } else if (parentMatch) {
          console.log('node', target, 'was removed through a removed parent!');
        }
    
      });
    });
    
    var config = {
      subtree: true,
      childList: true
    };
    observer.observe(document.body, config);
    
    
    var qs = document.querySelector.bind(document);
    qs('#ul').addEventListener('click', function(){qs('ul').remove();}, false)
    qs('#li').addEventListener('click', function(){qs('#to-be-removed').remove();}, false)
    <ul>
      <li>list item 1</li>
      <li>list item 2</li>
      <li id="to-be-removed">list item 3</li>
      <li>list item 4</li>
    </ul>
    
    <button id="ul">remove ul</button>
    <button id="li">remove li</button>