Reputation: 2148
Is it possible to determine when setting an innerHTML has loaded? I'm not sure if it's a synchronous operation. I assume the 'building the DOM' is synchronous, but loading tags, contents, etc isn't.
So in a nutshell - is there a way to get an event when innerHTML has completed loading?
Thanks!
Upvotes: 13
Views: 15670
Reputation: 1671
If your problem is waiting until innerHTML on an element has been completely rendered and painted, for example to measure the element's final size, use this code inside your top-level or async function:
await YieldForFrame();
await YieldForFrame();
where the following code is part of your program:
function YieldForFrame()
{
// Create Promise for use with 'await'
return new Promise(function(resolve, reject)
{
requestAnimationFrame(resolve);
});
} // YieldForFrame
Upvotes: 0
Reputation: 2718
It looks like @zahanm answer won't work if you replace the entire document HTML, which was what I needed. So I had to draw back to setInterval
. Based on @shawndumas answer I've created a more modern approach using Promise:
function waitUntilSelectorExist(selector, interval = 100, timeout = 20000) {
let intervalId;
let elapsed = 0;
let promise = new Promise(function(resolve, reject) {
intervalId = setInterval(() => {
let element = document.querySelector(selector);
if (element !== null) {
clearInterval(intervalId);
resolve(element);
}
elapsed += interval;
if (elapsed > timeout) {
clearInterval(intervalId);
reject(`The selector ${selector} did not enter within the ${timeout}ms frame!`);
}
}, interval);
});
return promise;
}
Also I use querySelector
instead, so you can search for whatever selector you like, either .class
, #id
, etc.
If the function ever find the querySelector
within the document the Promise
will resolve, so you can use it with the new await
keyword.
(async() => {
try {
await waitUntilSelectorExist("#test");
console.log("Do stuff!");
} catch (error) {
console.warn(error); // timeout!
}
})();
Of course you could also wrap around MutationObserver
within a Promise
if you are really just changing some elements within the document:
function waitUntilSelectorExist(selector) {
let MutationObserver = window.MutationObserver || window.WebKitMutationObserver;
let promise = new Promise(function(resolve) {
let observer;
observer = new MutationObserver(function(mutations) {
let element = document.querySelector(selector);
if (element !== null) {
observer.disconnect();
resolve();
}
});
observer.observe(document.body, { childList: true, subtree: true });
});
return promise;
}
Upvotes: 2
Reputation: 161
since img elements added through innerHTML do trigger their onload event you could add a tiny image at the end of your original code inserted in innerHTML, and in their onload event you could call a function. Also you can delete the image in there.
<img src='data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7' onload='hasLoadedFunc();this.parentNode.removeChild(this);'>
src='data:image' code is useful here since no specific image is needed.
I found this solution in another answer, I just can't find it. I will edit this solution once I find the reference.
Upvotes: 4
Reputation: 3276
Have you tried to use the window.onload
event? This event fires when the entire page is completely loaded including all its content like images, scripts, inner frames, etc.
P.S. If you use JQuery library, then you can use their $(window).load
event wrapper.
Upvotes: -2
Reputation: 354
How about creating a container div and add an onload event handler to it.
var container = document.createElement('div');
container.addEventListener('load', function() {
// Do something here
}, false);
container.innerHTML = '<h1>Here comes my HTML</h1>';
document.getElementById('someId').appendChild(container);
Upvotes: -2
Reputation: 993
You need to use DOM Mutation Observers, which currently only work in Chrome and Firefox. They replace the performance-killing DOM Mutation Events.
Example code, from HTML5Rocks:
var insertedNodes = [];
var MutationObserver = window.MutationObserver || window.WebKitMutationObserver;
var observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
for (var i = 0; i < mutation.addedNodes.length; i++)
insertedNodes.push(mutation.addedNodes[i]);
})
});
observer.observe(document, { childList: true });
console.log(insertedNodes);
Here is the DOM4 spec.
Please, don't use the setTimeout()
hacks. :)
Upvotes: 22
Reputation: 1413
var waitUntil = function (fn, condition, interval) {
interval = interval || 100;
var shell = function () {
var timer = setInterval(
function () {
var check;
try { check = !!(condition()); } catch (e) { check = false; }
if (check) {
clearInterval(timer);
delete timer;
fn();
}
},
interval
);
};
return shell;
};
Use it like this:
waitUntil(
function () {
// the code you want to run here...
},
function() {
// the code that tests here... (return true if test passes; false otherwise)
return !!(document.getElementById('<id of the div you want to update>').innerHTML !== '');
},
50 // amout to wait between checks
)();
Upvotes: 1
Reputation: 4555
Yes, you can do something like this:
window.document.getElementById("Testing").innerHTML =
"<img src='test.jpg' width='200' height='400'>";
alert('test');
The javascript will be executed sequentially and therefore the alert will go off once your innerHTML has been loaded.
Also, take a look at the Javascript Execution Model
Upvotes: -2