-1

Im using the jQuery load() function to bind to the onload event of images to gently transition them in.

Problem is if the image is already loaded before the image.load() function is called then the callback function never fires.

Is there a way to detect if an image has already been loaded before i call load()?

Reason being its a marionette application and moving between views images get cached and might already be loaded before the render function is called.

Basically my code where its at:

preloadImages: function () {
        var images = $('.grid .item > img');
        var initialHeight = images.eq(0).width();

        images.each(function(){
            $(this).height(initialHeight).css("opacity", 0);
            $(this).load(function(){
                $(this).css("height", "").animate({"opacity": 1}, 200);
            })
        });
    }
Dustin Silk
  • 4,320
  • 5
  • 32
  • 48
  • check this http://stackoverflow.com/questions/3877027/jquery-callback-on-image-load-even-when-the-image-is-cached – Umesh Sehta Sep 15 '14 at 08:12

1 Answers1

2

Is there a way to detect if an image has already been loaded before i call load()?

Yes. img elements have a complete flag, so:

images.each(function() {
    var $this = $(this);
    $this.on("load", handleLoad);
    if (this.complete) { // `this` = the DOM element
        $this.off("load", handleLoad);
        handleLoad.call(this);
    }
});

(Note that this is simplified, I've left out your code for measuring the first img — you'll want to wait to do that until it loads, unless you have CSS forcing a specific width — and used handleLoad rather than an inline function, which you'd have to move your load logic into.)

Note the order of things there:

  1. First, hook the load event.

  2. Then check complete.

  3. If complete is true, unhook load and call your handler directly.

Why do that? Because even though the main JavaScript UI thread is just one thread, the browser is not single-threaded. So if you did if (!this.complete) { $(this).on("load", handleLoad); }, it would be perfectly valid for the code to see that complete was not set, and then before you could hook the load event on the very next line, the browser fires the load event; since the browser inspects the list of registered event handlers at that point and doesn't find any, it doesn't queue any event callbacks. It would be unlikely, but valid.

Another way you can do it is with jQuery's one function, which registers a handler that unregisters itself on first call:

images.each(function() {
    var $this = $(this);
    $this.one("load.myload", handleLoad);
    if (this.complete) { // `this` = the DOM element
        $this.trigger("load.myload");
    }
});

Note the namespace (.myload). You don't want to fire other load handlers that may have already been fired or queued.

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • Awesome worked perfectly thanks My images in this case are all perfect squares and the width is set in css in % so grabbing that and setting the height equal to it works fine. Just to prevent an ugly load where divs are jumping all over the place. – Dustin Silk Sep 15 '14 at 08:28