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;
        } else if (window.addEventListener) { // browser support fallback
          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>',
        listEl = document.querySelector('ol');
    
    document.querySelector('body > button').onclick = function(e) {
      listEl.insertAdjacentHTML('beforeend', itemHTML);
    };
    
    // delete item
    listEl.onclick = function(e) {
      if (e.target.nodeName == 'BUTTON') {
        e.target.parentNode.parentNode.removeChild(e.target.parentNode);
      }
    }
        
    // Observe a specific DOM element:
    observeDOM(listEl, 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(){
       listEl.removeChild(listEl.lastElementChild);
       listEl.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>