Listening for changes in the DOM (Attributes, nodes, content etc) using the Mutation Observer in JavaScript

18 Jul 2019

I am learning about the Mutation Observer for work so that we can re-draw (render) information on the page when elements are added and removed dynamically.

The MutationObserver is a JavaScript feature that is similar to an event listener. It allows you to listen for changes in the DOM like when an attribute is changed, when an element is added or removed or when content is changed.

There are five main change scenarios that the Mutation Observer can be used to listen for. These are:

Most of the tutorials on Mutation Observers are pretty complicated. They show you how to listen for multiple change events at once, each with a chain of behaviours associated with them.

So I've just written up a simple example that allows you to watch for change events. Whenever a change occurs, two behaviours occur. The first is a simple alert message, the second is a console log of all of the change events that have happened so far, which the mutation observer tracks for you.

Create an instance of the MutationObserver

New mutation observer instance
      
        const mutationObserver = new MutationObserver(function(mutations) {
          alert("boo");
          mutations.forEach(function(mutation) {
            console.log(mutation);
          });
        });
      
    

The first thing we do above is create a new instance of the MutationObserver class and assign it to a variable called mutationObserver.

The mutation observer accepts a callback function as a paramater. This callback function also accepts an argument that I have called 'mutations' (common name used), which stores all of the changes that we are looking for in an array. Every time a new change occurs, the change is added to this mutations array argument.

The callback function contains the code that we want to execute whenever a new change that we are watching for occurs. In this case, there are two behaviours. The first behaviour is a simple message that pops up as an alert. You can substitute the alert for your own behaviour.

The second behaviour displays all of the change events that have occurred so far in the console. I used a forEach loop to do this. The mutation object stores information about the change event itself, and also information about the element that triggered the event.

Watch for the changes you are interested in

Now that we have our Mutation Observer object we can start listening for changes using the built-in observe method. The observe method takes two arguments. The first is the element you want to watch for changes. This can be the body of the document, a div container, a list etc. The second argument is a settings object. The settings object contains the change events you want to listen for. You can listen to one, a few or all of them at a time. Here is what the code for this looks like:

Setting what changes to observe
      
        const taskList = document.querySelector('.task-list');

        mutationObserver.observe(taskList, function({
          attributes: true,
          characterData: true,
          childList: true,
          subtree: true,
          attributeOldValue: true,
          characterDataOldValue: true
        });
      
    

If you don't want to watch for all of these changes, just include the change events you do want to observe. Changing the value to false will not stop them from being observed. For example, setting 'subtree' to false is telling the observer to only watch the target element for changes instead of all of its descendents.

Stop watching changes

To stop your MutationObserver from watching for change events and triggering behaviour when they occur, you can use the disconnect method which accepts no arguments, like this: mutationObserver.disconnect();