So I am creating my page in my companies template, which only allow us access to the body of the page. We don't have access to the head tag and there are scripts loaded on a lower part of the page that we don't have access to. One of these scripts dynamically loads an element onto the page. I need to run another script on that element, but because the element isn't loaded on the page until after my script has already ran I can't access that element. Is there a way I can check to see if that element has already been loaded on the page before running my script?
Let me know if I need to explain better.
<head>Don't have access</head>
<body>
<!--Needs to manipulate the element created by the companyScript.js-->
<script src="myScript.js"></script>
<!--Script that runs after mine, which I don't have access too-->
<script src="companyScript.js">
/*Dynamically adds <div class="element"></div> to page*/
</script>
</body>
Rewrote the 2020 code to use a MutationObserver
instead of polling.
/**
* Wait for an element before resolving a promise
* @param {String} querySelector - Selector of element to wait for
* @param {Integer} timeout - Milliseconds to wait before timing out, or 0 for no timeout
*/
function waitForElement(querySelector, timeout){
return new Promise((resolve, reject)=>{
var timer = false;
if(document.querySelector(querySelector)) return resolve();
const observer = new MutationObserver(()=>{
if(document.querySelector(querySelector)){
observer.disconnect();
if(timer !== false) clearTimeout(timer);
return resolve();
}
});
observer.observe(document.body, {
childList: true,
subtree: true
});
if(timeout) timer = setTimeout(()=>{
observer.disconnect();
reject();
}, timeout);
});
}
waitForElement("#idOfElementToWaitFor", 3000).then(function(){
alert("element is loaded.. do stuff");
}).catch(()=>{
alert("element did not load in 3 seconds");
});
This code will poll the DOM 10x/second and resolve a promise if it's found before the optional timeout.
/**
* Wait for an element before resolving a promise
* @param {String} querySelector - Selector of element to wait for
* @param {Integer} timeout - Milliseconds to wait before timing out, or 0 for no timeout
*/
function waitForElement(querySelector, timeout=0){
const startTime = new Date().getTime();
return new Promise((resolve, reject)=>{
const timer = setInterval(()=>{
const now = new Date().getTime();
if(document.querySelector(querySelector)){
clearInterval(timer);
resolve();
}else if(timeout && now - startTime >= timeout){
clearInterval(timer);
reject();
}
}, 100);
});
}
waitForElement("#idOfElementToWaitFor", 3000).then(function(){
alert("element is loaded.. do stuff");
}).catch(()=>{
alert("element did not load in 3 seconds");
});
function waitForElement(id, callback){
var poops = setInterval(function(){
if(document.getElementById(id)){
clearInterval(poops);
callback();
}
}, 100);
}
waitForElement("idOfElementToWaitFor", function(){
alert("element is loaded.. do stuff");
});
Sounds like a job for MutationObserver
!
A MutationObserver
is like an event listener: you can attach it to any DOM element to listen for changes:
var observer = new MutationObserver(function (mutationRecords) {
console.log("change detected");
});
The callback is passed an array of MutationRecord
s, which hold different lists of added/deleted/modified nodes.
Then, we attach the observer to any node:
observer.observe(document.body, {childList: true});
// second argument is a config: in this case, only fire the callback when nodes are added or removed
Note: IE support is not amazing. (surprise, surprise) Only works on IE 11. (Edge supports it, though.)
Here's another SO question about detecting changes to the DOM: Detect changes in the DOM
Snippet:
document.querySelector("button").addEventListener("click", function () {
document.body.appendChild(document.createElement("span"));
});
var observer = new MutationObserver(function (m) {
if (m[0].addedNodes[0].nodeName === "SPAN")
document.querySelector("div").innerHTML += "Change Detected<br>";
});
observer.observe(document.body, {childList: true});
<button>Click</button>
<div></div>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With