You can create a function that waits for a DOM element to exist before it executes in JavaScript.
There’s more than one way to achieve this, but the two best are arguably with a recursive function and by using the MutationObserver API.
In this tutorial, I will walk you through both of these methods and show you how to use them to get the job done. I will also walk you through the pros and cons of each, so you can decide which one to use for your needs.
Using a Recursive Function
Let’s use a recursive function with the setInterval
method which repeatedly calls a function with a fixed time delay between each call.
This will keep checking if the DOM element in question exists—and if it does, it will stop checking and call the function that you want to execute.
Here’s a simple example of the code:
function waitForElement(selector, callback, waitTime) {
// Check if an element matching the selector exists in the DOM
if (document.querySelector(selector)) {
// If the element is found, invoke the callback function
callback();
} else {
// If the element is not found at first, set up a timeout to recheck after waitTime
setTimeout(function() {
// Recursively call waitForElement with the same selector, callback, and waitTime values
waitForElement(selector, callback, waitTime);
}, waitTime);
}
}
We start by defining a function waitForElement
, which takes three parameters: selector
, callback
, and waitTime
.
The selector
parameter is a string containing one or more CSS selectors separated by commas. callback
is the function you want to execute after the element appears. Finally, waitTime
represents the delay (in milliseconds) between each attempt to find the element.
Here’s how you might use the updated function:
waitForElement("#myElement", function() {
console.log("The element now exists!");
}, 500);
In this case, the function will attempt to find an element with the ID #myElement
every half second (500 milliseconds). When the element appears, the script logs a message in the console.
You should be careful when using this method, as it could run indefinitely if the element never appears.
Using the MutationObserver API
The MutationObserver API provides developers a way to react to changes in a DOM.
It’s designed to react to changes in the DOM tree and is generally more efficient than the interval checking method, especially for web apps.
Here’s how you can use MutationObserver API to wait for an element:
function waitForElement(selector, callback) {
// Initialize a mutation observer
var observer = new MutationObserver(function(mutations, me) {
// Query for the element
var element = document.querySelector(selector);
if (element) {
callback(element);
// Once the element has been found, we can stop observing for mutations
me.disconnect();
return;
}
});
// Start observing the document with the configured parameters
observer.observe(document, { childList: true, subtree: true });
}
Let’s break down the steps in the function:
- We start by creating a new
MutationObserver
. This takes a callback function as an argument that will be invoked whenever a mutation is observed. The callback function is given a list ofMutationRecords
(stored inmutations
) and a reference to the observer (stored inme
). - Inside the callback function, we use
document.querySelector(selector)
to try to find the element we’re looking for. - If the element is found (
if (element)
), we call thecallback
function with the found element as a parameter, stop observing for mutations (me.disconnect()
), and return from the function. - Finally, outside the callback function but still inside
waitForElement
, we callobserver.observe
to start observing for mutations. Here, we’re observing the entiredocument
and looking for changes in thechildList
(nodes added or removed) andsubtree
(all descendants of the specified node) of thedocument
.
And here’s how you might use the waitForElement
function:
waitForElement('#myElement', function(element) {
console.log("The element now exists!", element);
});
While this method is typically more efficient than the interval checking method, it may still cause performance issues if not used correctly.
For instance, it could run indefinitely if the element never appears.
You may want to add additional conditions to stop observing after a certain period of time or a certain number of attempts.
To do this, you can add a timeout to the waitForElement
function by using setTimeout
. This will stop the function from running after a specified period of time.
Here’s the code:
function waitForElement(selector, callback, timeout) {
// Initialize a mutation observer
var observer = new MutationObserver(function(mutations, me) {
// Query for the element
var element = document.querySelector(selector);
if (element) {
callback(element);
// Once we have found the element, we can stop observing for mutations
me.disconnect();
return;
}
});
// Start observing the document with the configured parameters
observer.observe(document, { childList: true, subtree: true });
// Set a timeout to stop observing after the specified period of time
setTimeout(function() {
observer.disconnect();
console.log(`Element not found within ${timeout}ms. Disconnecting observer.`);
}, timeout);
}
And here’s how to call your function:
waitForElement('#myElement', function(element) {
console.log("The element #myElement now exists!", element);
}, 5000); // Timeout after 5,000ms (5 seconds)