Search code examples
javascriptdommutation-eventsmutation-observers

Detect changes in the DOM


I want to execute a function when some div or input are added to the html. Is this possible?

For example, a text input is added, then the function should be called.


Solution

  • Ultimate approach so far, with smallest code:

    (IE11+, FF, Webkit)

    Using MutationObserver and falling back to the deprecated Mutation events if needed:
    (Example below if only for DOM changes concerning nodes appended or removed)

    var observeDOM = (function(){
      var MutationObserver = window.MutationObserver || window.WebKitMutationObserver;
    
      return function( obj, callback ){
        if( !obj || obj.nodeType !== 1 ) return; 
    
        if( MutationObserver ){
          // define a new observer
          var mutationObserver = new MutationObserver(callback)
    
          // have the observer observe for changes in children
          mutationObserver.observe( obj, { childList:true, subtree:true })
          return mutationObserver
        }
        
        // browser support fallback
        else if( window.addEventListener ){
          obj.addEventListener('DOMNodeInserted', callback, false)
          obj.addEventListener('DOMNodeRemoved', callback, false)
        }
      }
    })()
    
    
    //------------< DEMO BELOW >----------------
    
    // add item
    var itemHTML = "<li><button>list item (click to delete)</button></li>",
        listElm = document.querySelector('ol');
    
    document.querySelector('body > button').onclick = function(e){
      listElm.insertAdjacentHTML("beforeend", itemHTML);
    }
    
    // delete item
    listElm.onclick = function(e){
      if( e.target.nodeName == "BUTTON" )
        e.target.parentNode.parentNode.removeChild(e.target.parentNode);
    }
        
    // Observe a specific DOM element:
    observeDOM( listElm, function(m){ 
       var addedNodes = [], removedNodes = [];
    
       m.forEach(record => record.addedNodes.length & addedNodes.push(...record.addedNodes))
       
       m.forEach(record => record.removedNodes.length & removedNodes.push(...record.removedNodes))
    
      console.clear();
      console.log('Added:', addedNodes, 'Removed:', removedNodes);
    });
    
    
    // Insert 3 DOM nodes at once after 3 seconds
    setTimeout(function(){
       listElm.removeChild(listElm.lastElementChild);
       listElm.insertAdjacentHTML("beforeend", Array(4).join(itemHTML));
    }, 3000);
    <button>Add Item</button>
    <ol>
      <li><button>list item (click to delete)</button></li>
      <li><button>list item (click to delete)</button></li>
      <li><button>list item (click to delete)</button></li>
      <li><button>list item (click to delete)</button></li>
      <li><em>&hellip;More will be added after 3 seconds&hellip;</em></li>
    </ol>