Using MutationObserver instead of DOMSubtreeModified - javascript

I was using DOMSubtreeModified and it worked as expected but have tried to change the code to use the MutationObserver way instead. My implementation is however not outputting to console but is also not giving me any errors?
// Select the node that will be observed for mutations
var targetNode = document.querySelector(".my-button");
// Options for the observer (which mutations to observe)
var config = { attributes: true, childList: true, subtree: true };
// Callback function to execute when mutations are observed
var callback = function(mutationsList, observer) {
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();
The html is:
<input type="submit" value="PRESS ME" class="my-button" disabled="disabled">

Related

Is there an event that triggers when a child element was removed and added? [duplicate]

This question already has answers here:
Detect changes in the DOM
(11 answers)
Closed 7 months ago.
say I have <ul>, I need to listen/watch when an <li> was removed and added.
Sure, you can use a MutationObserver to watch for changes in a DOM element.
The implementation of it is a little complex to describe in this answer, but the MDN article should provide you with all info you need.
Here's a contrived, and partially stolen example, to give you an idea:
const btnAdd = document.getElementById('btn-add');
const btnRemove = document.getElementById('btn-remove');
// Select the node that will be observed for mutations
const targetNode = document.getElementById('some-id');
btnAdd.addEventListener('click', () => {
const li = document.createElement('li');
targetNode.appendChild(li);
});
btnRemove.addEventListener('click', () => {
targetNode.removeChild(targetNode.children[0]);
});
// Options for the observer (which mutations to observe)
const config = { attributes: true, childList: true, subtree: true };
// Callback function to execute when mutations are observed
const callback = function(mutationList, observer) {
// Use traditional 'for loops' for IE 11
for (const mutation of mutationList) {
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
const observer = new MutationObserver(callback);
// Start observing the target node for configured mutations
observer.observe(targetNode, config);
<button id="btn-add">Add Item</button>
<button id="btn-remove">Remove Item</button>
<ul id="some-id"></ul>
Actually, i can't understand your question totally but there's an answer in my mind:
let ul = [];
ul[0] = Array.from(document.getElementById("myUl").children);
ul[1] = ul[0].length;
//Make an event to when to listen it e.g. setInterval
if (ul[0] < ul[1].length) { console.log("an li removed"); }
else if (ul[0] > ul[1].length) { console.log("an li added"); }

How to monitor multiple node insertions at different levels in dom using MutationObserver

I have a parent node in my dom. I have to call a method when a specific element is inserted in the parent node (newly inserted node is not a direct child, its a subtree, may be present at 2/3 level deep).
I have a code for single element insertion which works as expected
var parentNode = jQuery('.parent-node');
var observer = new MutationObserver(function (mutations) {
if (parentNode.find('.sub-class-1')[0] !== undefined) {
//call method
this.disconnect();
}
}).observe(parentNode[0], {childList:true, subtree: true });
But i want to execute callbacks for multiple sub elements creations. i tried this by using forEach on sub-class elements array.
arr.forEach(function (ob) {
new MutationObserver(function (mutations) {
if (parentNode.find(ob.className)[0] != undefined) {
//ob.callback()
this.disconnect();
}
}).observe(parentNode[0], { attributes:false, childList: true, subtree: true });
});
But after processing one subclass, it does not processes the rest subclasses. I guess we can only create on object on particular node.
So, how to detect all this nodes on creation to execute specific callbacks using MutationObserver or is there any better alternative approach.
Hi please try this,
var config = { attributes: true, childList: true, characterData: true };
var observers = [];
function createObserver(target, index) {
var observer = new MutationObserver(function(mutations) {
var $this = this;
mutations.forEach(function(mutation) {
if (parentNode.find('.sub-class-1')[0] !== undefined) {
$this.disconnect();
}else{
observers.push($this);
}
});
});
observer.observe(target, config);
}
$('.parent-node').each(function(i, el) {
createObserver(el, i)
});

Find class of newly appear DOM using mutation observer?

I want to detect what kind of item is coming after facebook's new post appear on users' feed when they scroll, I'm able to detect the new dom change but I'm stuck at mutation observer callback,
The $(this) isn't equal to the newly appear DOM, what I don't know what to do.
// Necessary for Facebooks "neverending" scrolling
var observer = new MutationObserver(function (mutations, observer) {
// fired when a mutation occurs
var x = $(this);
console.log(x) // I'm stuck here, what to do?
});
// pass in the target node, as well as the observer options
observer.observe($('[id^=topnews_main_stream_]').get(0), {
attributes: true,
childList: true,
characterData: true,
subtree: true
});
You should log variable mutations in callback function:
var observer = new MutationObserver(function (mutations, observer) {
mutations.forEach(function(mutation) {
console.log(mutation);
});
});
You can use mutations object to filter the type of mutation and its addedNodes property will return the newly add nodes
var observer = new MutationObserver(function (mutations, observer) {
mutations.forEach(function(mutation) {
if (mutation.type == "childList") {
console.log(mutation.addedNodes)
}
});
});
var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;
var list = document.querySelector('#form');
var observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
if (mutation.type === 'childList') {
console.log(mutation.addedNodes)
}
});
});
observer.observe(list, {
attributes: true,
childList: true,
characterData: true
});
setTimeout(function() {
var data = 'Publishing options';
jQuery("#form").append(data)
}, 5000)
<script src="https://ajax.aspnetcdn.com/ajax/jQuery/jquery-3.1.1.min.js"></script>
<form action="" method="post" id="form">
</form>

MutationObserver — only do something if nodes added, not removed

I have a MutationObserver that I'm using like so—
var config = {
attributes: false,
childList: true,
characterData: false,
subtree: true
};
var observer = new MutationObserver(function(mutations) {
//need to call function1() only when nodes are ADDED, not removed
});
var startObserving = function () {
target = document.getElementsByClassName("message-container")[0];
observer.observe(target, config);
}
I need to both add and remove elements to/from the container that the MutationObserver is watching, but I only want to execute function1() when nodes are added. Is there a way to do this? I've been reading the MDN article but can't think of a way to do this. Any help would be appreciated!
You should be able to check the addedNodes property on each of the mutations object to determine if elements were added. You’ll probably also want to validate that the type is childList.
Check out the MutationRecord page on the MDN.
Something like
var observer = new MutationObserver(function(mutations) {
var hasUpdates = false;
for (var index = 0; index < mutations.length; index++) {
var mutation = mutations[index];
if (mutation.type === 'childList' && mutation.addedNodes.length) {
hasUpdates = true;
break;
}
}
if (hasUpdates) {
function1();
}
});
I prefer do this using observer options childList and subtree. Then observer filtering changes
const observer = new MutationObserver((mutations) => {
// do something
});
observer.observe(node, {
childList: true, // detecting childList changes
subtree: true // detecing in childs
});

simple MutationObserver version of DOMNodeRemovedFromDocument

I attach some functionality to DOM elements and want to be able to clear all references when the element is removed from the DOM so it can be garbage collected,
My initial version to detect the removel of an element was this:
var onremove = function(element, callback) {
var destroy = function() {
callback();
element.removeEventListener('DOMNodeRemovedFromDocument', destroy);
};
element.addEventListener('DOMNodeRemovedFromDocument', destroy);
};
Then I read that mutation events were deprecated in favor of MutationObserver. So I tried to port my code. This is what I came up with:
var isDescendant = function(desc, root) {
return !!desc && (desc === root || isDecendant(desc.parentNode, root));
};
var onremove = function(element, callback) {
var observer = new MutationObserver(function(mutations) {
_.forEach(mutations, function(mutation) {
_.forEach(mutation.removedNodes, function(removed) {
if (isDescendant(element, removed)) {
callback();
// allow garbage collection
observer.disconnect();
observer = undefined;
}
});
});
});
observer.observe(document, {
childList: true,
subtree: true
});
};
This looks overly complicated to me (and not very efficient). Am I missing something or is this really the way this is supposed to work?
Actually... yes, there is a more elegant solution :).
What you added looks good and seems to be well optimized. However there is an easier way to know if the node is attached to the DOM or not.
function onRemove(element, onDetachCallback) {
const observer = new MutationObserver(function () {
function isDetached(el) {
if (el.parentNode === document) {
return false;
} else if (el.parentNode === null) {
return true;
} else {
return isDetached(el.parentNode);
}
}
if (isDetached(element)) {
observer.disconnect();
onDetachCallback();
}
})
observer.observe(document, {
childList: true,
subtree: true
});
}
I believe recursion is unnecessary to solve this problem, and that .contains() on the removednodes list is faster then traversing the entire dom for every arbitrary removal. Alternatively, you can define a custom event and apply that to any element you want to watch for the removal of, here's an example using a mutation observer to create a custom "removed" event.
const removedEvent = new Event("removed");
const observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation){
mutation.removedNodes.forEach(function(node) {
node.dispatchEvent(removedEvent);
});
});
});
observer.observe(document.documentElement {
childList: true,
subtree: true,
});
// Usage example:
let element = document.getElementById("anyelement");
// The custom event "removed" listener can be added before or after the element is added to the dom
element.addEventListener("removed", function() {
// Do whatever you need for cleaning up but don't disconnect the observer if you have other elements you need to react to the removal of.
console.info("Element removed from DOM.");
});

Categories

Resources