Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Event to determine when innerHTML has loaded

Tags:

javascript

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!

like image 603
Steve Avatar asked Aug 09 '11 18:08

Steve


People also ask

Which event triggers when object is loaded?

The load event is fired when the whole page has loaded, including all dependent resources such as stylesheets and images.

Which event occurs when page is loaded?

The onload event occurs when an object has been loaded. onload is most often used within the <body> element to execute a script once a web page has completely loaded all content (including images, script files, CSS files, etc.).


2 Answers

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;
}
like image 104
caiohamamura Avatar answered Oct 17 '22 07:10

caiohamamura


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. :)

like image 25
zahanm Avatar answered Oct 17 '22 07:10

zahanm