Detect changes in the DOM

Viewed 404426

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.

11 Answers

The following example was adapted from Mozilla Hacks' blog post and is using MutationObserver.

// Select the node that will be observed for mutations
var targetNode = document.getElementById('some-id');

// Options for the observer (which mutations to observe)
var config = { attributes: true, childList: true };

// Callback function to execute when mutations are observed
var callback = function(mutationsList) {
    for(var mutation of mutationsList) {
        if (mutation.type == 'childList') {
            console.log('A child node has been added or removed.');
        }
        else if (mutation.type == 'attributes') {
            console.log('The ' + mutation.attributeName + ' attribute was modified.');
        }
    }
};

// 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);

// Later, you can stop observing
observer.disconnect();

Browser support: Chrome 18+, Firefox 14+, IE 11+, Safari 6+

MutationObserver = window.MutationObserver || window.WebKitMutationObserver;

var observer = new MutationObserver(function(mutations, observer) {
    // fired when a mutation occurs
    console.log(mutations, observer);
    // ...
});

// define what element should be observed by the observer
// and what types of mutations trigger the callback
observer.observe(document, {
  subtree: true,
  attributes: true
  //...
});

Complete explanations: https://stackoverflow.com/a/11546242/6569224

Use the MutationObserver interface as shown in Gabriele Romanato's blog

Chrome 18+, Firefox 14+, IE 11+, Safari 6+

// The node to be monitored
var target = $( "#content" )[0];

// Create an observer instance
var observer = new MutationObserver(function( mutations ) {
  mutations.forEach(function( mutation ) {
    var newNodes = mutation.addedNodes; // DOM NodeList
    if( newNodes !== null ) { // If there are new nodes added
        var $nodes = $( newNodes ); // jQuery set
        $nodes.each(function() {
            var $node = $( this );
            if( $node.hasClass( "message" ) ) {
                // do something
            }
        });
    }
  });    
});

// Configuration of the observer:
var config = { 
    attributes: true, 
    childList: true, 
    characterData: true 
};

// Pass in the target node, as well as the observer options
observer.observe(target, config);

// Later, you can stop observing
observer.disconnect();

8 years later, here is my solution using MutationObserver and RxJS

observeDOMChange(document.querySelector('#dom-changes-here'))
  .subscribe(val => log('DOM-change detected'));

The main difference from the other approaches is to fire a CustomEvent when DOM changes, and listen to the event debounced to execute user logic efficiently with the following features;

  • Debounce consecutive DOM changes to prevent too many executions
  • Stop watching after the given time
  • Removes event listeners/subscribers after stop watching DOM changes
  • Useful to watch DOM change happened in a framework, e.g., Angular
import { fromEvent, timer} from 'rxjs';
import { debounceTime, takeUntil, tap } from 'rxjs/operators';

function observeDOMChange(el, options={}) {
  options = Object.assign({debounce: 100, expires: 2000}, options);

  const observer = new MutationObserver(list =>  {
    el.dispatchEvent(new CustomEvent('dom-change', {detail: list}));
  });
  observer.observe(el, {attributes: false, childList: true, subtree: true });

  let pipeFn;
  if (options.expires) {
    setTimeout(_ => observer.disconnect(), options.expires);
    pipeFn = takeUntil(timer(options.expires));
  } else {
    pipeFn = tap(_ => _); 
  }

  return fromEvent(el, 'dom-change')
    .pipe(pipeFn, debounceTime(options.debounce));
}

Demo at stackblitz.
enter image description here

Use TrackChanges for detect html changes. Link: https://www.npmjs.com/package/track-changes-js

Example

 let button = document.querySelector('.button');

 trackChanges.addObserver('buttonObserver', () => button);
 
 trackChanges.addHandler('buttonObserver', buttonHandler);

 function buttonHandler(button) {
   console.log(`Button created: ${button}`);
 }

Found the question so updating with a solution in 2022.

We have seen different solutions which mostly involve MutationObserver.

If anyone wants to record the DOM changes and store them to replay after some time, they can use rrweb

Related