1

i have a simple html, that i want an event to trigger once the last image is loaded, or if there is an error on the last image being loaded. here is my code

html

<div id="compare-table-scrollable">
    <img src="www.bla.com/1.png" />
    <img src="www.bla.com/2.png" />
    <img src="www.bla.com/3.png" />
</div>

Jquery

var imageCount = $('#compare-table-scrollable img').length;
var counterIMG = 0;
$('#compare-table-scrollable img').one("load error",function(){
           counterIMG++;
           if (counterIMG == imageCount)  // do stuff when all have loaded
           {
                alert(counterIMG);
           }
});

here is my FIDDLE

Greg
  • 481
  • 1
  • 5
  • 21
user2636556
  • 1,905
  • 4
  • 32
  • 61
  • `load` events don't work reliably with images. [Here's what you can do about it](http://stackoverflow.com/questions/3877027/jquery-callback-on-image-load-even-when-the-image-is-cached). – Blazemonger Sep 30 '13 at 15:55
  • @Blazemonger: `load` events **do** work reliably with images. You just have to be sure you're there to catch them. If you're not (if you set `src` before you've hooked the event), you may miss it. That's not the same thing as the event being unreliable. – T.J. Crowder Sep 30 '13 at 17:43
  • @T.J.Crowder [It's well-known to the jQuery developers that if an image is cached, the browser's normal `load` event may not be triggered at all.](http://api.jquery.com/load-event/) You seem to be describing "reliable under certain circumstances," which is not what I'd consider "reliable" at all. – Blazemonger Sep 30 '13 at 17:53
  • @Blazemonger: I'm quite sure that the jQuery developers know as well as I do that `load` is reliable **if you do things correctly**. But in the face of too many people hooking the event **after** setting `src`, a big yellow warning in the docs is not out of line at all (although it should be reworded). I would say "`load` events don't work reliably with images" is the greater falsehood by far than "`load` events only work reliably if you hook the event before setting `src`" Obviously, feel free to point me at an evidence-based article with replicatable code demoing a missing `load` event. :-) – T.J. Crowder Sep 30 '13 at 17:56
  • @T.J.Crowder I'd be happy to point you to a project I had myself a year or so ago, but sadly I already fixed the code using [this plugin](https://github.com/desandro/imagesloaded). The problem was exactly as described: large rotating background images were sometimes firing the `load` event, but usually weren't, because the browser was pulling them from the cache. – Blazemonger Sep 30 '13 at 18:01

2 Answers2

2

Here's one I wrote myself a while back. It's very similar to what you have above, but a little more robust...

function onImagesLoaded($container, callback) {
    var $images = $container.find("img");
    var imgCount = $images.length;
    if (!imgCount) {
        callback();
    } else {
        $("img", $container).each(function () {
            $(this).one("load error", function () {
                imgCount--;
                if (imgCount == 0) {
                    callback();
                }
            });
            if (this.complete) $(this).load();
        });
    }
}

And how to use it...

onImagesLoaded($("#compare-table-scrollable"), function() {
    alert("images loaded");
});

Notice the addition of if (this.complete), which allows the function to count images that are cached and therefore load before the function is called.

Reinstate Monica Cellio
  • 25,975
  • 6
  • 51
  • 67
0

You're not hooking the events until very late in the page load process, after the events have already fired. Note the second drop-down box on the upper left side of jsFiddle, which says "onload". This is jsFiddle's extremely surprising default, which is to wrap your JavaScript code in a window load event handler. That handler doesn't get fired until all the images have loaded or failed to load.

If you change that drop-down to no wrap - <body>, you get the alert: http://jsfiddle.net/X4AmG/3/

That said, with the images being specified in the markup, I'd be worried about a load or error event managing to get fired before your code hooked up its handlers. For that reason, I'd probably do something like this instead:

// Get the images
var imgs = $('#compare-table-scrollable img');

// Schedule the first check for DOM ready
$(checkForImagesDone);

// Our check function
function checkForImagesDone()
{
  var counter = 0;
  imgs.each(function()
  {
    if (this.complete)
    {
      ++counter;
    }
  });
  if (counter === imgs.length)
  {
    alert("All complete");
  }
  else
  {
    setTimeout(checkForImagesDone, 50); // 50ms
  }
}
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • For some reason I thought he was using document ready event. My fault ;) – Claudio Redi Sep 30 '13 at 15:59
  • @ClaudioRedi: Do you have a reference for `load` and `error` not firing earlier? I'd **love** to know for sure that they won't. :-) But I find it hard to buy it, not least as jQuery's DOM ready varies from browser to browser... – T.J. Crowder Sep 30 '13 at 16:00
  • I can't tell for sure that this applies for ALL browsers but document ready event [doesn't wait for all assets to be loaded](http://api.jquery.com/ready/). I do think it is safer to assume that this restriction applies to all browser and use windows load instead of document ready if we need all assets to be loaded :) – Claudio Redi Sep 30 '13 at 16:50