3

I have a code that post to a php script that reads all files in a folder and returns them, all of them are img's, the jquery parses the information, on a var that's an array each image is saved as an img object with the src , width, height and attr, on successed I want to check if each image is loaded and then finally on complete fire another function and remove a div. But I don't know how to check if the image has loaded completely, I've been fooling around with .complete but it never seem's to load, the function calls itsef upon until the img is loaded and then returns true so it can keep going. here's the code, it's kind of messy and probably not a nice coding.

var gAllImages = [];
function checkFed()

{
    var leni = gAllImages.length;   
    for (var i = 0; i < leni; i++) {


        if (!gAllImages[i].complete) {
            var percentage = i * 100.0 / (leni);
            percentage = percentage.toFixed(0).toString() + ' %';
            console.log(percentage);
            //  userMessagesController.setMessage("loading... " + percentage);
            checkFed();

            return;

        }

    //userMessagesController.setMessage(globals.defaultTitle);
    }
}


 if($('slideshow')){
 var topdiv = '<div id="loading"><div class="centered"><img src="/karlaacosta/templates/templatename/images/ajax-loader.gif" /></div> </div>';
    $('#overall').append(topdiv);
    //console.log('alerta');
    var jqxhr = $.post('http://localhost/karlaacosta/templates/templatename/php/newtest.php', function(data){



        var d = $.parseJSON(data);
        //console.log(d[1]);



        if(typeof(d) == 'object' && JSON.parse){
            var len = d.length;
            //console.log(len);



            for(var i = 0; i < len; i++){
                var theImage = new Image();
                var element = d[i].split('"');
                //        console.log(element);
                //      console.log(element[4]);
                theImage.src = '/karlaacosta/images/Fotografia/TODO'+element[0];
                theImage.width = element[2];
                theImage.height = element[4];                   
                theImage.atrr = element[6];
                gAllImages.push(theImage);

            }





        // console.log(html);
        }else{
            console.log('error');
        }
    }).success(function (){




    setTimeout('checkFed', 150);




    }).error(function(){
        var err = '<div id="error"><h2>Error: Lo sentimos al parecer no se pueden cargar las imagenes</h2></div>';
        $('#loading').append(err);

    }).complete(
        function(){
            var len = gAllImages.length;
            var html = '<ul class="slides">'    
            for(var i = 0; i < len; i++){
                html += '<li><img src="'+gAllImages[i].src+'" width="'+gAllImages[i].width+'" height="'+gAllImages[i].height+'" attr="'+gAllImages[i].attr+'" /></li>';


            }
            html += '</ul>';
            $('#slideshow').append(html);
        }
        );
 jqxhr.complete(function(){
    //
    imageSlide();
    $('#loading').remove();
    //
    console.log('completed');
});
}

If I take out the recursivity of checkFed() obviously the script finishes and when the images are put on the html they are loaded fine and fast, are in the cache never being loaded? any other sugestions on other parts of the code are also welcomed.

Samuel Lopez
  • 2,250
  • 5
  • 27
  • 39
  • You can use the img load callback. http://stackoverflow.com/questions/3877027/jquery-callback-on-image-load-even-when-the-image-is-cached – lucuma May 15 '12 at 22:01
  • 1
    I don't have time to analyze and answer this right now, but just note that `setTimeout(checkFed(), 4000);` does **not** schedule `checkFed` to run four seconds from now. It runs `checkFed` *right away* and then passes its *return value* to `setTimeout`. I don't see that `checkFed` returns a function, so that might be part of the problem. Remove the `()` from after `checkFed` if your goal is to schedule it to run four seconds later. – T.J. Crowder May 15 '12 at 22:03
  • I would like to answer this question but I do not have time at the moment. It seems the provided answers won't make the cut. – Alexander May 15 '12 at 22:10

2 Answers2

7

I want to check if each image is loaded and then finally on complete fire another function and remove a div. But I don't know how to check if the image has loaded completely

Fundamentally, checking for image load success is simple:

var theImage = new Image();
var element = d[i].split('"');
$(theImage).load(function() {
    // The image has loaded (from cache, or just now)
    // ...do something with the fact the image loaded...
});
theImage.src = '/karlaacosta/images/Fotografia/TODO'+element[0];

The key thing above is to hook the load event before you set its src. If you set src first, and the image is in cache, the load event can fire before the next line of code hooking it, and you'll miss it.


Here's an example: Live copy | source

HTML:

<img src="http://www.gravatar.com/avatar/ca3e484c121268e4c8302616b2395eb9?s=32&d=identicon&r=PG">
<p>When you see the image above, 
<input type="button" id="theButton" value="Click Me"></p>

JavaScript:

jQuery(function($) {

  $("#theButton").click(function() {
    var img = document.createElement('img');
    $(img).load(function() {
      display("Image <code>load</code> event received");
    });
    img.src = "http://www.gravatar.com/avatar/ca3e484c121268e4c8302616b2395eb9?s=32&d=identicon&r=PG";
    document.body.appendChild(img);
  });

  function display(msg) {
    $("<p>").html(msg).appendTo(document.body);
  }
});

As you can see, I'm using the same img src in each case. And reliably on every browser I've ever tried, I do receive the load event.

T.J. Crowder
  • 879,024
  • 165
  • 1,615
  • 1,639
  • but how can it check if the images is completely loaded if it doesn't have the src? are you just attaching a event so then it can check if it's complete? – Samuel Lopez May 15 '12 at 22:41
  • 1
    @SamuelLopez: *You're* not checking; the browser does that for you. First you hook the event. Then you set the `src`, which allows the image to load (it can't load without `src`). At that point, if the image is in cache, the `load` event callback will be scheduled; but if you haven't hooked it yet, it won't be because the browser will look at the event handler chain and see that there aren't any handlers hooked. The callback will actually execute the next time the JS engine (which is single-threaded in this case) is idle, which will be after a (very) short pause. – T.J. Crowder May 15 '12 at 22:45
  • @SamuelLopez: Added an example. – T.J. Crowder May 15 '12 at 22:47
  • 2
    The .load event will not fire on some browsers after it is cached. You have to check for a cached copy. – Fresheyeball May 15 '12 at 23:49
  • @Fresheyeball: Do you have a reference for that? In my experience, if you do things in the right order (see above), `load` is 100% reliable. – T.J. Crowder May 16 '12 at 02:47
  • @SamuelLopez: Good deal, glad that helped. – T.J. Crowder May 16 '12 at 02:48
  • http://stackoverflow.com/questions/3877027/jquery-callback-on-image-load-even-when-the-image-is-cached http://stackoverflow.com/questions/3588102/jquery-load-not-working-on-my-image – Fresheyeball May 16 '12 at 02:51
  • http://api.jquery.com/load-event/ see cavets for .load its in jquery's documentation – Fresheyeball May 16 '12 at 02:51
  • @Fresheyeball: Again, **if you do things in the right order**, `load` is 100% reliable. The questions you linked are hooking it after `src` is set. That creates a race condition and it's no surprise people find it not working reliably; races are like that. I believe that's the problem the jQuery docs are referring to as well (the first caveat; the others aren't relevant). If you can prove that hooking `load` **before** setting `src` is unreliable on any browser, I'd be interested in seeing that. I've tested it extensively and never had it fail. – T.J. Crowder May 16 '12 at 03:00
  • http://www.witheringtree.com/2009/05/image-load-event-binding-with-ie-using-jquery/ here's another one. Its actually a known limitation reported by the jquery foundation itself. – Fresheyeball May 16 '12 at 03:00
  • @Fresheyeball: From that witheringtree link: *"The only way I could get it to work in IE was add the image element to the DOM but don’t give it a src. Once the image element was added to the DOM, I created the load event listener. Once the load even was created, then I went back to the image and gave it an src."* So again, if you do things in the right order... – T.J. Crowder May 16 '12 at 03:01
  • You may be right here, I've just had weird problems even with the proper order of operations. I've encountered the misfire in ie7-8 as well as some editions for firefox. However it does not happen every time. – Fresheyeball May 16 '12 at 03:03
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/11287/discussion-between-fresheyeball-and-t-j-crowder) – Fresheyeball May 16 '12 at 03:03
  • @Fresheyeball: I don't do the chat thing when it's relevant to a question/answer. (One of the ways in which I completely disagree with [the old?] SO management.) If you can demonstrate `load` failing with an example where `load` is hooked *before* setting `src` on a new element, by all means post a link to http://jsbin.com or similar (not fiddle, doesn't work in older IEs), I'd be very interested in seeing it. [This works in every browser I've tried](http://jsbin.com/enagig) and I've tried IE6 onward, Firefox, Safari, Opera, Chrome, Midori, Konqueror, ... :-) (Have to get to work for now...) – T.J. Crowder May 16 '12 at 03:10
  • I finally see the difference in what I am doing. I really learned something here. You are totally right @T.J.Crowder thank you. The difference is between loading through js, or trying to get a .load from an existing dom element. You are a cool dude. – Fresheyeball May 16 '12 at 16:25
  • @Fresheyeball: Hey, that's very kind. I'm glad this discussion helped! And indeed, *you're* absolutely right that if the element is already in the DOM with a `src` on it, you can't count on the `load` event (it may have fired the instant that the `img` was parsed, before your JS had a chance to hook the event). It's a classic race condition, but for some reason we don't initially see it that way, not until we think it through quite closely. :-) Best, – T.J. Crowder May 16 '12 at 17:07
  • @T.J.Crowder I am now considering that a better pluggin than the existing ones, would be to place the source in a data attribute on the element, and then loop through and move the src. This might be a more reliable way to provide load events to existing dom elements. – Fresheyeball May 16 '12 at 17:51
1

Its not doable in a reliable cross browser way without a plugin, due to browser caching and event model weirdness. Try imagesLoaded or waitForImages.

https://github.com/desandro/imagesloaded

https://github.com/alexanderdickson/waitForImages

Fresheyeball
  • 28,195
  • 19
  • 94
  • 160
  • 3
    ... if a plugin can do it, why can't native code? that's all a plugin is right? – Kevin B May 15 '12 at 22:03
  • This is true, you can always right your own system, but these plugins are mature and reliable. If you want take a look at how they are written if you want to see the challenge here. – Fresheyeball May 15 '12 at 22:04
  • thanks for the links for the plug-ins ill check them out all tough I prefer not to use plug-ins – Samuel Lopez May 15 '12 at 22:12
  • I was checking those plug-ins but it looks like they check for the DOM elment if it's loaded and I want to check if the images are preloaded in the cache, or did I miss something? I just took a quick look I'll check them in detail later – Samuel Lopez May 15 '12 at 22:16
  • thats basically it. If you can replicate it in a reliable way without the plugin, and wish too do so, more power to you. – Fresheyeball May 15 '12 at 22:16