I'd like to offer another solution to the AJAX problem that is more modern and elegant.
Brock's script, like most solutions, are using setInterval() or setTimeout() at the core to check for elements periodically, so they can't respond instantly and there is always some delay. Other solutions uses onload events, which will often fire earlier than you want on dynamic pages.
The solution: Use MutationObserver() to directly listen for DOM changes to respond immediately after an element is inserted
(new MutationObserver(check)).observe(document, {childList: true, subtree: true});
function check(changes, observer) {
if(document.querySelector('#mySelector')) {
observer.disconnect();
// actions to perform after #mySelector is found
}
}
The check function fires immediately after every DOM change. This allows you to specify arbitrary trigger conditions so you can wait until the page is in the exact state required before you execute your own code.
Note that, this may be slow if the DOM changes very often or your condition takes a long time to evaluate, so instead of observing document, try to limit the scope by observing a DOM subtree that's as small as possible.
This method is very general and can be applied to many situations. To respond multiple times, just don't disconnect the observer when triggered.
Another use case is if you're not looking for any specific element, but just waiting for the page to stop changing, you can combine this with a idle timer that gets reset when the page changes.
var observer = new MutationObserver(resetTimer);
var timer = setTimeout(action, 3000, observer); // wait for the page to stay still for 3 seconds
observer.observe(document, {childList: true, subtree: true});
// reset timer every time something changes
function resetTimer(changes, observer) {
clearTimeout(timer);
timer = setTimeout(action, 3000, observer);
}
function action(observer) {
observer.disconnect();
// code
}
You can listen for attribute and text changes as well. Just set attributes and characterData to true in the options
observer.observe(document, {childList: true, attributes: true, characterData: true, subtree: true});
And if you want to use it in an async/await paradigm, you can do something like
function wait_element(root, selector) {
return new Promise((resolve, reject) => {
(new MutationObserver(check)).observe(root, {childList: true, subtree: true});
function check(changes, observer) {
let element = root.querySelector(selector);
if(element) {
observer.disconnect();
resolve(element);
}
}
});
}
let node = await wait_element(document, '#mySelector');
(function init(){var counter = document.getElementById('id-of-element');if (counter) { /* do something with counter element */ } else { setTimeout(init, 0);}})();to continously poll for the existence of the element. That's most generic solution.@run-atvalues which includedocument-idleandcontext-menuwhich may be of use. It also appears that Greasemonkey is adding support fordocument-idlealthough it hasn't been documented as of yet.