I had a requirement where I need to know if something got changed in the DOM i.e. any element was added/removed or attribute(s) were modified.
I needed a simple mechanism to detect all sorts of DOM changes and then I learned about MutationObserver
.
MutationObserver
lets us watch for changes being made in the DOM tree. We can even target the specific DOM element to watch for changes.
Let’s start with simple markup
<h1>Today's menu</h1> <div id="parent"> <ul id="menu"> <li>🍕Pizza </li> <li>🍩 Doughnut</li> <li>🍔 Hamburger</li> </ul> </div>
First, we need to select the target node which we want to observe for any changes
const list = document.getElementById('menu');
Next, we need to create an instance of MutationObserver
// get handle of target element const list = document.getElementById('menu'); // create an observer instance const observer = new MutationObserver();
MutationObserver
accepts a callback
that gets called when element under observation mutates.
Let’s create callback logMutations
and pass it to MutationObserver
. The callback function takes two input parameters i.e. mutations
& observer
which invoked the callback.
// get handle of target element const list = document.getElementById('menu'); // callback for mutation observer const logMutations = function(mutations, observer) { mutations.forEach(function(mutation) { console.log(mutation.type); }); } // create an observer instance const observer = new MutationObserver(logMutations);
In logMutations
callback function, we are iterating over the mutations array and logging them to console.
You can even filter the results based on mutation.type
as follows
const logMutations = function (mutations) { mutations.forEach(function (mutation) { if (mutation.type === "childList") { console.log(`${mutation.type} - list updated`); } }); };
Last, thing is to start observing the target element as follows
// get handle of target element const list = document.getElementById('menu'); // callback for mutation observer const logMutations = function(mutations, observer) { mutations.forEach(function(mutation) { console.log(mutation.type); }); } // create an observer instance const observer = new MutationObserver(logMutations); // start observing target element observer.observe(list, { childList: true });
Last line in above code i.e. observer.observe
accepts following inputs
list
in our caseFor complete list please visit MDN docs
Our MutationObserver
is ready to log items on console. Let’s quickly add a button to dynamically add items to list
<h1>Today's menu</h1> <Button id="addItem" onclick="addFoodItem()">Add New Item</Button> <div id="parent"> <ul id="menu"> <li>🍕Pizza </li> <li>🍩 Doughnut</li> <li>🍔 Hamburger</li> </ul> </div>
We will be calling following function when user click on Add New Item
button
function addFoodItem() { let entry = document.createElement("li"); entry.appendChild(document.createTextNode("🍬Candy")); list.appendChild(entry); }
Open developer console and click on “Add New Item” button. You should see following output in console
childList - list updatedMutationObserver
can be used to detect changes in element, attribute, child nodes etc.MutationObserver
instance takes callback functionMutationObserver
callback function accepts inputs i.e. mutations and observer