Zze Zze - 6 months ago 22
jQuery Question

Recall window load event - javascript

I am going to do my best here to distinctly explain what my issue is without the use of jsfiddle because

$(window).on("load")
does not fire within their IDE.

I have a html 'wrapper' which dynamically loads (ajax) html into
div.content
.

<body>
<div class="header"></div>
<div class="overlay"></div>


<div class="loader hidden" align="center">
<img src="images/loading.gif" />
</div>

<!-- Container for the content -->
<div class="content">
<!-- dynamic content appears here -->
</div>



<div class="footer"></div>
</body>


At the start of a new piece of content being loaded, I toggle the visibility between the loading gif and the content div.

$(".content").toggleClass("hidden", true);
$(".loader").toggleClass("hidden", false);


At the end of the loading /ajax process I have the following code:

$(".content").load("screens/"+this.currentScreen+"/"+this.currentScreen + ".html .screen", function( response, status, xhr )
{
//other code
//
//
$(window).on("load", function() {
$(".content").toggleClass("hidden", false);
$(".loader").toggleClass("hidden", true);
});
});


I chose
$(window).on("load")
because I only want
div.content
to be visible again once all the images have finished loading, as opposed to
$(document).ready()
.

For the first piece of content to be loaded, this works perfectly. However for the second piece of content, the
$(window).on("load")
event never fires.

I have a hunch that this event is not allowed to be invoked a second time, or maybe it is unbound after being called?

I tried triggering / invoking the method but to no avail.

if((window.onload) === null)
{
$(window).on("load", function() {
console.log("$(window).on('load') called");
$(".content").toggleClass("hidden", false);
$(".loader").toggleClass("hidden", true);
});
}
else
{
$(window).trigger("load");
}


Also, I assure everyone that it isn't the content being loaded, because if I replace
$(window).on("load")
with
$(document).ready()
it works fine. I just desperately want to wait for the new images to have loaded.

How can I achieve this?

The Fix



Thanks to @trincot's help I used the ImagesLoaded Plug-in.
I thought I would just take a second to update my question, because the solution I am currently using doesn't exactly match the code which @trincot provided.

$(".content").load("screens/"+this.currentScreen+"/"+this.currentScreen + ".html .screen", function( response, status, xhr )
{
//other code
//
//
$(document).ready(function() {
$("body > .content img").each(function(index, element) {
$(this).attr("src", ("screens/"+ currentScreenName + "/" + $(this).attr("src")));
});
$(document).ready(function() {
$(".content").imagesLoaded(function() {
$(".content").toggleClass("hidden", false);
$(".loader").toggleClass("hidden", true);
});
});
});
});


As you can see I ended up still needing a
$(document).ready(function(){})
because I needed to wait for the DOM to update the paths to all the images. Without
$(document).ready(function(){})
the
imagesloaded
function was superfluous. The
imagesloaded
function was still the catalyst for achieving my desired results.

Answer

The window's load event only executes once. Even when you dynamically add content, it will not be triggered. This behaviour is indeed different from ready(), where jQuery will call the callback always, even if the document is ready when it meets this code for the first time.

When adding content dynamically there is no "one-liner" to get a callback run when all images of that content have been loaded. The code you would need to write, would have to capture the load event for every image you load, and see which one was last, also taking care of images that did not load (because of an invalid reference, or they were cached).

The ImagesLoaded Plug-in provides a method that does all that. You can use it like this:

$(".content").load("screens/"+this.currentScreen+"/"+this.currentScreen + ".html .screen", function( response, status, xhr ) 
{
    //other code 
    //
    //
    $(".content").imagesLoaded( function() {
        // images have loaded
        $(".content").toggleClass("hidden", false);
        $(".loader").toggleClass("hidden", true);
    });
});

So I would suggest to just include that plug-in, like this:

<script src="https://npmcdn.com/imagesloaded@4.1/imagesloaded.pkgd.min.js">
</script>

and use the imagesLoaded() method, like above code.