I am developing a JavaScript module, which knows nothing about the environment in which it will be used in.
And, technically speaking, I want to implement the next function:
onceAppended(element, callback);
element
is an HTMLElement
and the parent of this element may be unknown during the module initialization. callback
is a function, which must be triggered once element
appears on the page.
Callback must be called immediately if the element is appended to the document. In case element
is not appended yet, function will trigger callback
once element
appears on the document.
The problem is, we can detect element
append event with using DOMNodeInserted
mutation event. But mutation events are now deprecated. And it seems that MutationObserver
can't handle this task, can it?
Here is my code snippet:
function onceAppended (element, callback) {
let el = element,
listener;
while (el.parentNode)
el = el.parentNode;
if (el instanceof Document) {
callback();
return;
}
if (typeof MutationObserver === "undefined") { // use deprecated method
element.addEventListener("DOMNodeInserted", listener = (ev) => {
if (ev.path.length > 1 && ev.path[ev.length - 2] instanceof Document) {
element.removeEventListener("DOMNodeInserted", listener);
callback();
}
}, false);
return;
}
// Can't MutationObserver detect append event for the case?
}
We can detect if an element has been added to DOM using the MutationObserver object. This provides the ability to observe for changes being made to the DOM tree.
contains() method checks if an element is inside another, and returns a boolean: true if it is, and false if it's not. Call it on the parent element, and pass the element you want to check for in as an argument. // returns true main. contains(list); // returns false main.
var element = document. getElementById('elementId'); if (typeof(element) != 'undefined' && element != null) { // Exists. }
append() method inserts a set of Node objects or string objects after the last child of the document. String objects are inserted as equivalent Text nodes. This method appends a child to a Document . To append to an arbitrary element in the tree, see Element.
Unfortunately there is no way to do this exactly the same way as with DOMNodeInserted
because none of the MutationObserver
events tell you when an element's parent changes.
Instead, you'll have to place the observer on the document.body
and check each node that gets appended. If you want to run your callback whenever any node is appended, that's easy. If you only want it to run when certain nodes are appended, then you'll have to keep a reference to those nodes somewhere.
let elements = [];
elements[0] = document.createElement('div');
elements[1] = document.createElement('span');
elements[2] = document.createElement('p');
elements[3] = document.createElement('a');
const MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;
const observer = new MutationObserver(function(mutations) {
// 'addedNodes' is an array of nodes that were appended to the DOM.
// Checking its length let's us know if we've observed a node being added
if (mutations[0].addedNodes.length > 0) {
// 'indexOf' let's us know if the added node is in our reference array
if (Array.prototype.indexOf.call(mutations[0].addedNodes[0], elements) > -1) {
// Run the callback function with a reference to the element
callback(mutations[0].addedNodes[0]);
}
});
observer.observe(document.body, {
childList: true,
subtree: true
});
function callback(element) {
console.log(element);
}
document.body.appendChild(elements[2]); // => '<p></p>'
elements[2].appendChild(elements[3]); // => '<a></a>'
As you can see the callback is triggered for nodes appended anywhere within document.body
. If you want callback()
to run whenever any element is appended, just take out the second check if the element exists in your reference array.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With