19

Possible Duplicate:
Official way to ask jQuery wait for all images to load before executing something

I'm writing a jQuery plugin that handles a bunch of image animations with a simple call to the plugin function (something like $("#image1").anims() where #image1 is an image), however as part of the plugin's functionality I use $(this).width() to get the width of the image right at the start of the function call.

But, since the plugin function is called in $(document).ready, it's trying to get the width of the image before the image has loaded, so it's always returning 0. Is there a workaround for this?

Community
  • 1
  • 1
Jackie
  • 1,630
  • 2
  • 15
  • 12
  • [The solution](http://stackoverflow.com/questions/544993/official-way-to-ask-jquery-wait-for-all-images-to-load-before-executing-something) on SO. – ybo Mar 05 '09 at 18:28

8 Answers8

13

http://docs.jquery.com/Events/load

$("#image1").load(function () {
$("#image1").anims();
});
Thomas Stock
  • 10,927
  • 14
  • 62
  • 79
3

You could preload the image

var oImage = new Image();

oImage.onload = function(){
    this.width// width of loaded image
}

oImage.src = '/path/to/image.gif';

$(document).ready won't wait for images to load, it waits for the dom to be ready.

Simon
  • 37,815
  • 2
  • 34
  • 27
2

If you are interjecting trusted html with jQuery.append() or jQuery.html() into "element1" and your css value of element2 be it div or span is floated left to fit element3 you will not be able to get offsetWidth , clientWidth , naturalWidth (google crome) of element3 with out a new event trigger.

var element1 = $('div.container');
while(i<=length){
var element2 = $('<span/>').attr({'id':''+[i]+'','class':'container'});
var element3 = $('<img/>').attr('src':''+source[i]+'','class':'img');
$(element1)children().remove();
$(element2).appendTo(element1).append(element3);
var elms = $(element3);
var chwidth = elms[i].offsetWidth // returns 0;
++i;
};

what you can do is return the context width of the elements before they're loaded.

while(i<=length){
$(element1).children().remove();
$(elemen2).appendTo(element1).append(element3);
var elms = $(element3);
var newelms = elms[i].load();
var chwidth = newelms[i]['context'].width // returns element3's contextual width
if(chwidth != 0) // make sure only the proper width is returned 
var width = chwidth;
++i;
};

If this doesn't work then try:

while(i<=length){
$(element1).children().remove();
$(elemen2).appendTo(element1).append(element3);
var elms = $(element3);
var newelms = elms[i].load(function (){
//get the widths inside the load context
var width = this.width();
//pass the single width or el[i].width to next function
};
++i;
};
  • uhhh... I kind of hope someone played around with my solution only to find out that after interjecting element2 to element1 and element3 to element2, you can use : var element1 = document.getElementById(''+element1.attr('id')+''); var span = element1.children; for(i=0;i – Boyd Culver Nov 03 '12 at 18:55
  • No need to preload or use the load event. :) – Boyd Culver Nov 03 '12 at 19:02
1

Interjecting trusted HTML and getting the widths without triggering a new event can be done by accessing its DOM context after the trusted HTML is interjected with document.getElementById() like so:

var element1 = $('element#one');
var element1id = element1.attr('id');
var newElement1 = document.getElementById(''+element1id+'');
var newElement2 = newElement1.children;
var widths = [];
for (var i = 0; i < newElement2.length; ++i) {
   var img = newElement2[i].children;
   widths[i] = img[0].width;
}

Then just use the widths array to get the widths.

John Kugelman
  • 349,597
  • 67
  • 533
  • 578
1

Do a fadeIn before reading any dimensions:

$('#image').fadeIn(10,function () {
    var tmpW = $(this).width();
    var tmpH = $(this).height();
});
Nikola K.
  • 7,093
  • 13
  • 31
  • 39
Dio
  • 11
  • 1
0

I believe you can use

$(this).ready(function() {
    // stuff with $(this).width() in here
})

I do not think .ready() is exclusive to the document.

Community
  • 1
  • 1
Logan Serman
  • 29,447
  • 27
  • 102
  • 141
0

By the time $(document).ready is called, the image should already have been loaded. Something else is wrong.

If you need to know the width of the image before you start the animation, but the image needs to be in some form of hidden state when the animation starts, you could capture the image's width using .width() before the animation, and call .hide() or whatever else is appropriate, immediately after measuring the width.

tw16
  • 29,215
  • 7
  • 63
  • 64
Jaanus
  • 17,688
  • 15
  • 65
  • 110
  • 1
    $(document).ready only guarantees the DOM is ready, not assets (like stylesheets, images or other JavaScripts). – rfunduk Mar 05 '09 at 18:31
-3

You could use a setTimeout() function to delay the execution long enough for the image to load.

Here is an example of how it works:

setTimeout("alert('hello world');", 5000);

The first argument is a string that your javascript engine will parse as executing code and the second argument is an integer value that represents how many milliseconds you wish to delay before the code in your first argument executes.

Andrew Hare
  • 344,730
  • 71
  • 640
  • 635
  • 2
    Will the amount of milliseconds necessary change depending on computer/internet connection speed? Ideally it would be ready ASAP, so I wouldn't want to delay it by ten seconds or anything, but I also wouldn't want to leave slowpokes in the dark. – Jackie Mar 05 '09 at 18:29