4

I'm using a jQuery plugin that invokes a callback once all images on page have been loaded. It checks the imageObject.complete property and binds a handler to the load and error events to determine when image loading is done.

This works well, but the problem I'm running into is that, even though an image is considered loaded, when I inspect the height and width properties of the image or its containing div element, the dimensions have not yet been updated.

Here's an example:

http://jsfiddle.net/RtnVx/12/

How can I ensure that the containing element has been resized to fit the image before attempting to access its height and width dimensions?

EDIT 1: I cleaned up and commented the code in my jsfiddle to make the example easier to understand.

EDIT 2: There must be a race condition or variation based on caching because when I run the code from a different machine, it works properly (i.e., the top margin is calculated properly), which is actually not good because it is not consistent. The inconsistencies are more apparent in Chrome, FWIW.

Also, to be clear, the goal isn't to call init every time an image loads; rather, init should be called once after all images have been loaded via the AJAX load invocation.

Rob Sobers
  • 20,737
  • 24
  • 82
  • 111

1 Answers1

3

Answer: http://jsfiddle.net/morrison/RtnVx/30/

You needed to not call batchImageLoad until the image was done loading. I created an event on the loaded image.

Updated Notes:

  • I cut out your jQuery plug-in. It was overly complex and I didn't completely understand it.
  • My current solution provides error handling by using the error event, as did the plug-in.
  • The solution process:
    • Find all the img's descending from #slides and store that length in a .data() attribute, as well as a variable to keep how many have loaded.
    • Bind a load and error events on each img which updates the count of loaded images.
    • If the count of loaded/errored images hits the total image count, call setTimeout() until all of them have widths greater than zero then fire init().
Rob Sobers
  • 20,737
  • 24
  • 82
  • 111
Levi Morrison
  • 19,116
  • 7
  • 65
  • 85
  • Thanks for the answer! But `batchImageLoad` doesn't call back to `init` until all of the images are done loading, so it shouldn't matter when I call it, right? Also, your code will call `init` for *every* image. I want to call `init` *once* after all images are loaded. (I realize my example only has one image.) – Rob Sobers May 23 '11 at 22:55
  • @Levin Thanks for the update. Your jsfiddle gives me a 404 page, though. The plugin also binds `load` and `error` to all image elements and also checks for `image.complete` in case an image is in cache (in which case `load` won't fire). The crux of the issue is that even though an image is loaded, its `height` and `width` properties won't necessarily have updated yet. This behavior is especially inconsistent in Chrome, I find. I think we figured out how to wait for all images to load. Now we have to figure out how to hook into the height & width being set. – Rob Sobers May 25 '11 at 01:54
  • @Rob Jsfiddle has been having problems with that, recently. Try the updated link now. – Levi Morrison May 25 '11 at 11:41
  • @Levi jsfiddle is back up. Your code is nice and simple and accomplishes what the `batchImageLoad` plugin does, but is still running into the issue that, even though the images are done loading, their dimensions haven't been updated. – Rob Sobers May 25 '11 at 13:28
  • @Rob You want to use `centerSlides()` after images are loaded, but they are not always resized in time and `centerSlides()` therefore works incorrectly. Correct? – Levi Morrison May 25 '11 at 14:13
  • @Levi That's correct. As a solution, I think I'm going to have to call `setTimeout` in the `load` event handler to check if `height > 0`. Thanks so much for your help! – Rob Sobers May 25 '11 at 17:32
  • @Rob Don't disregard this quite yet. I think I may have a very elegant solution. I'm not quite sure if it will work at the moment, but I'll let you know. – Levi Morrison May 25 '11 at 17:35
  • @Rob try out the latest solution. – Levi Morrison May 25 '11 at 19:01
  • @Levi Thanks for all your work on this. It's been fun! Calling `setTimeout` until the heights/widths are set does the trick. I wish we had an "dimensions updated" event to hook into, but this will do. – Rob Sobers May 29 '11 at 16:16