Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JQuery - Check when image is loaded?

Tags:

jquery

I am having a bit of trouble working out when an image has been loaded.

I have been told that the following function will work but it isn't doing anything.

$("#photos img:first").load(function (){
    alert("Image loaded!");
});

There are no error's in my code. Everything else in my script works great.

My HTML looks like this.

<div id="photos">
    <img src="../sample1.jpg" style="background-color:#000033" width="1" height="1" alt="Frog!"/>
    <img src="../sample2.jpg" style="background-color:#999999" width="1" height="1" alt="Zooey!"/>
</div>

Do I have the wrong JQuery function? It should also be noted that the visibility is set to hidden. However even when visible there is no alert.

Any ideas?

like image 478
JasonS Avatar asked May 14 '10 09:05

JasonS


2 Answers

The load event of an image is fired when it's loaded (doh!), and critically, if you don't hook up your handler before it loads, your handler won't get called. Browsers will load resources in parallel, so you can't be sure (even in jQuery's ready event saying the page's DOM is ready) that the image hasn't already been loaded when your code runs.

You can use the complete property of the image object to know whether it's already been loaded, so:

var firstPhoto = $("#photos img:first");
if (firstPhoto[0].complete) {
    // Already loaded, call the handler directly
    handler();
}
else {
    // Not loaded yet, register the handler
    firstPhoto.load(handler);
}
function handler() {
    alert("Image loaded!");
}

There may even be a race condition in that, if the browser in question really implements multi-threaded loading where the image load may occur on a different thread than the Javascript thread.

Of course, if your selector will match multiple images, you'll need to handle that; your selector looks like it's supposed to match only one, so...

Edit This version allows for multiple images, and I think it handles any non-Javascript race conditions (and of course, at present there are no Javascript race conditions; Javascript itself is single-threaded in browsers [unless you use the new web workers stuff]):

function onImageReady(selector, handler) {
    var list;

    // If given a string, use it as a selector; else use what we're given
    list = typeof selector === 'string' ? $(selector) : selector;

    // Hook up each image individually
    list.each(function(index, element) {
        if (element.complete) {
            // Already loaded, fire the handler (asynchronously)
            setTimeout(function() {
                fireHandler.call(element);
            }, 0); // Won't really be 0, but close
        }
        else {
            // Hook up the handler
            $(element).bind('load', fireHandler);
        }
    });

    function fireHandler(event) {
        // Unbind us if we were bound
        $(this).unbind('load', fireHandler);

        // Call the handler
        handler.call(this);
    }
}

// Usage:
onImageReady("#photos img:first");

A couple of notes:

  • The callback doesn't get the event object; you could modify it to do so if you liked, but of course, there'd be no event in the case where the image is already loaded, so it would be of limited utility.
  • You could probably use one instead of bind and unbind, but I like the clarity and I'm paranoid. :-)
like image 169
T.J. Crowder Avatar answered Oct 11 '22 15:10

T.J. Crowder


Use the ready instead of load event.

like image 32
ThiefMaster Avatar answered Oct 11 '22 14:10

ThiefMaster