Event to determine when innerHTML has loaded

Viewed 13233

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!

7 Answers

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);'>

JSFiddle sample

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.

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;
}
Related