The MutationObserver interface offers the capability to monitor changes made to the DOM tree. This feature is designed to supersede the older Mutation Events functionality that was part of the DOM3 Events specification.
In intricate web applications, the Document Object Model (DOM) can frequently undergo alterations. As a result, there may be instances when your application must respond to specific changes within the DOM. The MutationObserver interface provides a means to monitor these modifications to the DOM.
JavaScript MutationObserver Syntax
- Utilizing MutationObserver is quite simple. To begin, you should define a callback function to instantiate an observer, similar to the following example:
- The subsequent procedure involves appending it to a DOM node, which can be executed as detailed below:
let obs_var = new MutationObserver(callback);
obs_var.observe(node, config);
Config is an object with parameters defining the changes to respond to and is returned by the function.
- childList: alterations to the node's immediate children.
- subtree: every descendent of a node.
- attributes: characteristics of the node.
- attributeFilter: A list of attribute names that allows you to see the ones you want to see.
- characterData: for node observation.
The callback is executed subsequent to any changes. The observer serves as the second entity, while the alterations are transferred to the first parameter in the form of an array of MutationRecord objects.
How to operate JavaScript MutationObserver
In order to utilize the MutationObserver API, you must begin by:
- First, you need to define the callback function that will be executed whenever there are alterations in the DOM:
- Subsequently, create an instance of the MutationObserver and pass the callback function to the object's constructor through the MutationObserver method:
function callback(mutations) {
// JavaScript program
}
let observer = new MutationObserver(callbackFunction);
- Next, initiate the observation of changes within the DOM by invoking the observe method.
observer.observe(targetNode, observerOptions);
The observe function comprises two parameters. The target parameter refers to the root of the node subtree that you wish to monitor for any alterations. The observerOptions parameter dictates which DOM modifications should be reported to the observer's callback function.
- To cease monitoring the DOM updates, invoke the disconnect method.
observer.disconnect;
Examples
The subsequent illustrations demonstrate the utilization of the JavaScript MutationObserver API with an alternative category of data.
Example1
The subsequent example illustrates the fundamental JavaScript MutationObserver API, accompanied by straightforward information.
<!DOCTYPE html>
<html>
<body>
<h2> JavaScript MutationObserver Function</h2>
<div contentEditable id="elemobsId"> Click here and <b> ADD </b>...</div>
<script>
let observer_var = new MutationObserver(mutationdata => {
alert("changes happen");
});
// observe each data of the changes except attributes
observer_var.observe(elemobsId, {
childList: true, // observe direct children list
subtree: true, // observe direct lower descendants
characterDataOldValue: true, // pass old data to callback
});
</script>
</body>
</html>
Output
The image below illustrates the output generated by a fundamental JavaScript MutationObserver.
Output 1
Insert the characters in the input field
Output 2
After inserting the characters
Example 2
The example below demonstrates the fundamental usage of the JavaScript MutationObserver API with an option set to false.
<!DOCTYPE html>
<html>
<body>
<h2> JavaScript MutationObserver Function</h2>
<div contentEditable id="elemobsId"> Click here and <b> ADD </b>...</div>
<script>
let optiondata = {
childList: false, // observe direct children list
subtree: false, // observe direct lower descendants
characterDataOldValue: false, // pass old data to callback
}
let observer_var = new MutationObserver(mutationdata => {
alert("changes happen");
});
// observe each data of the changes except attributes
observer_var.observe(elemobsId, optiondata);
</script>
</body>
</html>
Output
The image below illustrates the output generated by a fundamental JavaScript MutationObserver.
JavaScript MutationObserver options
You can specify options to define the characteristics of the MutationObserver by providing them as the second argument to the observe function:
let choices= {
childList: true,
attributes: true,
characterData: false,
subtree: false,
characterDataOldValue: false
attributeFilter: ['attr1', 'attr2'],
attributeOldValue: false,
};
It is not necessary to select every option available. Nevertheless, it is essential that at least one of the following properties is set to true: childList, attributes, or characterData for the MutationObserver to operate correctly; failing to do so will result in the observer method generating an error.
The following properties are included in the MutationRecord object:
- type: The mutation's type. It is either "characterData," "attributes," or "childList."
- target: where the change takes place.
- addedNodes/removedNodes: the newly or recently added nodes.
- The added or removed nodes' previousSibling or nextSibling, respectively.
- attributeName/attributeNamespace: the new name or namespace for the attribute.
- oldValue: The previous value is only for text or attribute changes if attributeOldValue/characterDataOldValue is set as the matching option.
Example
The subsequent illustration demonstrates the fundamental usage of the JavaScript MutationObserver API, incorporating various options.
<!DOCTYPE html>
<html>
<body>
<h2> JavaScript MutationObserver Function</h2>
<div id = "elemobsId"> Click here and <b> ADD </b></div>
<ul contentEditable id = "programming_language">
<li> Java </li>
<li> PHP </li>
<li> JavaScript </li>
<li> PYTHON </li>
<li> PERL </li>
</ul>
<script>
let list_data = document.querySelector('#programming_language');
let option_data = {
childList: true,
attributes: true,
characterData: false,
subtree: false,
attributeFilter: ['one', 'two'],
attributeOldValue: false,
characterDataOldValue: false
};
let observer_var = new MutationObserver(mutationdata => {
alert("changes happen");
});
// observe each data of the changes except attributes
observer_var.observe(list_data, option_data);
</script>
</body>
</html>
Output
The image below illustrates the fundamental output of a JavaScript MutationObserver.
Observe the changes in a child element
The mutation method provides the ability to demonstrate functionalities such as starting, stopping, adding, and removing child elements. The subsequent steps illustrate how to implement changes in the child element of the function.
- In this section, we can generate a list of data in HTML format.
- Develop buttons to implement the desired functionality within the HTML.
- Utilize the query selector in JavaScript to establish a variable that references both the buttons and the data attribute.
<ul id = "programming_language">
<li> Java </li>
<li> PHP </li>
<li> JavaScript </li>
<li> PYTHON </li>
<li> PERL </li>
</ul>
<button id = "dataStart"> Start Button </button>
let list_data = document.querySelector('#programming_language');
let dataStart = document.querySelector('#dataStart');
Utilize the mutation function along with a callback that incorporates the variable.
function log_data(mutation data) {
for (let mutation of mutation data) {
if (mutation.type === 'childList') {
console.log(mutation);
}
}
}
let observer_var = new MutationObserver(log_data);
- Include the necessary actions utilizing the mutationobserver variable along with a JavaScript function.
dataStart.addEventListener('click', function () {
// create a new item element
let item_value = document.createElement('li');
item_value.textContent = `Bootstrap version ${counter++}`;
// append it to the child nodes of list
list_data.appendChild(item_value);
});
Examples
The subsequent illustrations demonstrate the child list along with its associated data through various operations.
Example 1
The illustration demonstrates the fundamental modifications occurring within the child element of the parent element.
<!DOCTYPE html>
<html>
<body>
<h2> JavaScript MutationObserver Function</h2>
<ul id = "programming_language">
<li> Java </li>
<li> PHP </li>
<li> JavaScript </li>
<li> PYTHON </li>
<li> PERL </li>
</ul>
<div id = "elemobsId"> Click on the button </div>
<button id = "dataStart"> Start Button </button>
<button id = "dataStop"> Stop Button </button>
<script>
let list_data = document.querySelector('#programming_language');
let dataRemove = document.querySelector('#dataRemove');
let dataStop = document.querySelector('#dataStop');
function log_data(mutation data) {
for (let mutation of mutation data) {
if (mutation.type === 'childList') {
console.log(mutation);
}
}
}
let observer_var = new MutationObserver(log_data);
dataStop.addEventListener('click', function () {
observer_var.disconnect();
// set button states to disconnect MutationObserver Function
dataStart.disabled = false;
dataStop.disabled = true;
});
dataStart.addEventListener('click', function () {
observer_var.observe(list_data, {
childList: true
});
dataStart.disabled = true;
dataStop.disabled = false;
});
</script>
</body>
</html>
Output
The illustration displays the result produced by the JavaScript MutationObserver when monitoring the child element.
Output1
Click start button
Output2
Click stop button
Example 2
The illustration demonstrates the process of adding data within the child element of its parent element.
<!DOCTYPE html>
<html>
<body>
<h2> JavaScript MutationObserver Function</h2>
<ul id = "programming_language">
<li> Java </li>
<li> PHP </li>
<li> JavaScript </li>
<li> PYTHON </li>
<li> PERL </li>
</ul>
<div id = "elemobsId"> Click on the button </div>
<button id = "dataStart"> Add Button </button>
<script>
let list_data = document.querySelector('#programming_language');
let dataStart = document.querySelector('#dataStart');
function log_data(mutation data) {
for (let mutation of mutation data) {
if (mutation.type === 'childList') {
console.log(mutation);
}
}
}
let observer_var = new MutationObserver(log_data);
let counter = 1;
dataStart.addEventListener('click', function () {
alert('New Child element is added');
// create a new item element
let item_value = document.createElement('li');
item_value.textContent = `Bootstrap version ${counter++}`;
// append values to the child nodes of a given list
list_data.appendChild(item_value);
});
</script>
</body>
</html>
Output
The displayed image illustrates the results produced by the JavaScript MutationObserver in conjunction with the child element.
Output1
Before inserting the last element
Output2
After inserting the last element
Example 3
The example illustrates the data that has been removed from the child element of the parent element.
<!DOCTYPE html>
<html>
<body>
<h2> JavaScript MutationObserver Function</h2>
<ul id = "programming_language">
<li> Java </li>
<li> PHP </li>
<li> JavaScript </li>
<li> PYTHON </li>
<li> PERL </li>
</ul>
<div id = "elemobsId"> Click on the button </div>
<button id = "dataRemove">Remove Button </button>
<script>
let list_data = document.querySelector('#programming_language');
let dataRemove = document.querySelector('#dataRemove');
function log_data(mutation data) {
for (let mutation of mutation data) {
if (mutation.type === 'childList') {
console.log(mutation);
}
}
}
let observer_var = new MutationObserver(log_data);
dataRemove.addEventListener('click', function () {
// Delete the last item element of the list
alert('Child element is removed);
list_data.lastElementChild ?
list_data.removeChild(list_data.lastElementChild) :
alert('No more child element to remove');
});
</script>
</body>
</html>
Output
The provided image illustrates the result after the final element of the list has been removed.
Output1
Before removing the last element
Output2
After removing the last element
Keep in mind the mutationObserver crucial details.
- The callback function, which I've given the name mCallback to demonstrate that you may give it any name, will activate every time a valid mutation is discovered and following the conclusion of the watch method.
- Since childList is the only "kind" of acceptable mutation, it makes sense to search for it when looping through the MutationRecord. In this case, searching for any other type would be useless.
- A text node can be added or removed from the targeted element using childList, which would also count. This means that it is not necessary to add or remove an element.
Conclusion
The JavaScript MutationObserver method allows for monitoring and manipulating lists. Through this functionality, we can interact with the list and its associated child elements using a variety of options.