Removing loader animation after iframes have loaded

803 views Asked by At

I am maintaining a web application that has all of its contents within iframes. A quick break down of its structure: (each '-' represents a new layer)

Main page
-iframe container
--iframe q1
--iframe q2
--iframe q3
--iframe q4
--iframe q5

Basically, there are 4 iFrames inside of a main one. I have a loader animation that I need to remove from the screen after all of the iframes have finished loading. Each iframe has data that is updated by selections made on the page. What I need is for the loading animation to cover the entire screen after each update is made. What is the best approach to handle this? I know you can use

$('#iframe').on('load',function() {
      //code here...
}

to determine when an iframe is finished loading. Is there a way to simple way to listen for all of them at once and then to turn off the loading animation once they are done? Thank you for your help.

Here is how each iframe is created :

var p1HTML = '<div id='p1ContainerBody' class='panelContainerBody'><iframe id='P1ChartFrame' src='' frameborder='0' scrolling='no' style='height: 100%; width: 100%'></iframe></div>'

and then:

if (ConfigData["GlobalOptions"].Quadrants[x].QuadrantId == "1") { $("#q1Container").html(p1HTML); }

1

There are 1 answers

3
zero298 On BEST ANSWER

Create a Promise for each iframe and add a load listener as you discussed in your second code block. Resolve the Promise in the load event listener after the iframe loads. Create a Promise.all() handler to remove the animation after all the iframes load.

Promise.all(Array.prototype.map.call(document.querySelectorAll("iframe"), function (iframe) {
    return new Promise(function (resolve, reject) {
        iframe.addEventListener("load", function () {
            resolve();
        });
    });
})).then(function () {
    // Do loading removal
});

jQuery has its own Promise API if you would prefer to stay within the jQuery framework.

The main thing that you will need to do to facilitate this is to keep a handle to the iframes so that you can attach explicit load handlers to them before you change the urls that they point to. If you don't, you may miss the load event in the case where the the location is cached or something.

Consider this alternative code:

var urlArr, iframeProms;

// Array of urls that we need to make iframes for
urlArr = [
    "http://www.google.com",
    "http://www.yahoo.com"
];

// Map the urls to an array of objects containing iframe elements and associated promises
iframeProms = $.map(urlArr, function (url) {
    var d, iframe;

    // Make a deferred that we will resolve on iframe load
    d = $.Deferred();

    // Make an iframe
    iframe = $("iframe");

    // Add a load listener BEFORE YOU ADD THE URL
    iframe.on("load", function () {
        // Resolve the deferred
        d.resolve();
    });

    // Now provide the url so we don't miss timing for load event
    iframe.src = url;

    // Return a handle to the iframe and the deferred's promise
    return {
        i: iframe,
        p: d.promise
    };
});

// Map down to the promises and what for them to resolve
$.when($.map(iframeProms, function (i) {
    return i.p;
})).then(function () {
    // Do loading removal
});