How to wait until an element exists?
DOMNodeInserted
is being deprecated, along with the other DOM mutation events, because of performance issues - the recommended approach is to use a MutationObserver to watch the DOM. It's only supported in newer browsers though, so you should fall back onto DOMNodeInserted
when MutationObserver
isn't available.
let observer = new MutationObserver((mutations) => { mutations.forEach((mutation) => { if (!mutation.addedNodes) return for (let i = 0; i < mutation.addedNodes.length; i++) { // do things to your newly added nodes here let node = mutation.addedNodes[i] } })})observer.observe(document.body, { childList: true , subtree: true , attributes: false , characterData: false})// stop watching using:observer.disconnect()
I was having this same problem, so I went ahead and wrote a plugin for it.
$(selector).waitUntilExists(function);
Code:
;(function ($, window) {var intervals = {};var removeListener = function(selector) { if (intervals[selector]) { window.clearInterval(intervals[selector]); intervals[selector] = null; }};var found = 'waitUntilExists.found';/** * @function * @property {object} jQuery plugin which runs handler function once specified * element is inserted into the DOM * @param {function|string} handler * A function to execute at the time when the element is inserted or * string "remove" to remove the listener from the given selector * @param {bool} shouldRunHandlerOnce * Optional: if true, handler is unbound after its first invocation * @example jQuery(selector).waitUntilExists(function); */$.fn.waitUntilExists = function(handler, shouldRunHandlerOnce, isChild) { var selector = this.selector; var $this = $(selector); var $elements = $this.not(function() { return $(this).data(found); }); if (handler === 'remove') { // Hijack and remove interval immediately if the code requests removeListener(selector); } else { // Run the handler on all found elements and mark as found $elements.each(handler).data(found, true); if (shouldRunHandlerOnce && $this.length) { // Element was found, implying the handler already ran for all // matched elements removeListener(selector); } else if (!isChild) { // If this is a recurring search or if the target has not yet been // found, create an interval to continue searching for the target intervals[selector] = window.setInterval(function () { $this.waitUntilExists(handler, shouldRunHandlerOnce, true); }, 500); } } return $this;};}(jQuery, window));
Here is a core JavaScript function to wait for the display of an element (well, its insertion into the DOM to be more accurate).
// Call the below functionwaitForElementToDisplay("#div1",function(){alert("Hi");},1000,9000);function waitForElementToDisplay(selector, callback, checkFrequencyInMs, timeoutInMs) { var startTimeInMs = Date.now(); (function loopSearch() { if (document.querySelector(selector) != null) { callback(); return; } else { setTimeout(function () { if (timeoutInMs && Date.now() - startTimeInMs > timeoutInMs) return; loopSearch(); }, checkFrequencyInMs); } })();}
This call will look for the HTML tag whose id="div1"
every 1000 milliseconds. If the element is found, it will display an alert message Hi. If no element is found after 9000 milliseconds, this function stops its execution.
Parameters:
selector
: String : This function looks for the element ${selector}.callback
: Function : This is a function that will be called if the element is found.checkFrequencyInMs
: Number : This function checks whether this element exists every ${checkFrequencyInMs} milliseconds.timeoutInMs
: Number : Optional. This function stops looking for the element after ${timeoutInMs} milliseconds.
NB : Selectors are explained at https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelector