The objective and what I've tried
I'm trying to get a method to be able to wait until an element is already in the DOM. I've read a few articles about MutationObserver
, and I got this method which should accomplish what I need:
const waitForElement = async (queryString) => {
return new Promise((resolve) => {
const observer = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
const nodes = Array.from(mutation.addedNodes);
nodes.forEach((node) => {
console.log('NODE CUSTOM', node);
if (node.matches && node.matches(queryString)) {
observer.disconnect();
resolve(node);
}
});
});
});
observer.observe(document.documentElement, {
childList: true,
subtree: true,
});
});
};
Then, I could simply use it this way:
await waitForElement('#id-of-element');
The problem
The thing is that it is actually not working as expected: the console.log
only logs the "parents" elements, and if the element to be searched is deep in the tree, it seems not to log it (this is being used in a more complex application, so it may have to do with async calls and so on).
The question
However, I found that, in stead of going through arrays of mutations and nodes, I only need to see if the actual element is in the DOM, so I implemented this:
const waitForElement = async (queryString) => {
return new Promise((resolve) => {
let element;
const observer = new MutationObserver(() => {
element = document.querySelector(queryString);
if (element) {
observer.disconnect();
resolve(element);
}
});
observer.observe(document.documentElement, {
childList: true,
subtree: true,
});
});
};
This approach will just check if, after each mutation, the element is actually on the DOM using the querySelector
method. It actually works (where the other one fails), and I find it easier to read and understand, and with less loops in between.
Is this a recommendable approach? Will it affect performance, or it will be just the same as the first approach?
Thank you!