Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Having a reference to an element, how to detect when it is appended to the document?

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?
}
like image 517
ZitRo Avatar asked Jul 26 '16 11:07

ZitRo


People also ask

How do you check if an element is added to DOM?

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.

How do you check if an element contains another element?

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.

How do you know if an element is present?

var element = document. getElementById('elementId'); if (typeof(element) != 'undefined' && element != null) { // Exists. }

How does the append () method insert an element into the document?

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.


1 Answers

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.

like image 72
skyline3000 Avatar answered Oct 21 '22 09:10

skyline3000