Reputation: 482
I'm trying test for when an image is loaded so I can change the opacity and fade it in, and I want to do this to all images with the .hphoto
class.
This is how I'm attempting it with jQuery:
function handle_photoloads() {
$(".hphoto").each(function (i,obj) {
console.log("Yo");
if ($(obj).complete) {
console.log("1");
$(obj).css('opacity','1');
} else {
console.log("incomplete");
$(obj).on('load',function () {
console.log("2");
$(obj).css('opacity','1');
});
}
});
}
$(document).ready(function() {
handle_photoloads();
});
The outputs I get are "Yo" and "incomplete", and I get one of each output for the amount of .hphoto
objects I have, so something is working. Why is the load handler not being triggered as expected?
Upvotes: 0
Views: 93
Reputation: 1074008
This line is a problem:
if ($(obj).complete) {
You're looking for a complete
property on the jQuery object, not the DOM element it wraps. Since obj
refers to the DOM element, the simplest thing is:
if (obj.complete) { // Where `obj` refers to the DOM element
Otherwise, use prop
, but you wouldn't normally use it when you're wrapping something you know is an element:
if ($(obj).prop("complete")) { // Where `obj` refers to the DOM element
However, note that checking for the complete
flag and then adding a handler has a small chance of missing the event. JavaScript in browsers has only one UI thread, but the browser is not single-threaded. This is a perfectly valid sequence of events:
The JavaScript interpreter evaluates $(obj).prop("complete")
and gets back the value false
.
The browser's image loading code, running on a different thread, sees that it has finished loading that image and checks to see if there are any event handlers registered for the load
event; not seeing any, it doesn't add any handler callback for when the UI thread is next able to process the pending calls queue.
The JavaScript interpreter hooks the load
event on the image.
The odds are very low, but it can happen.
If you're worried about it, hook the handler first, then check complete
and, if it's set, call your handler and unregister it. In a rare converse of the above, you might get two calls rather than one (because the event occurred after you hooked the handler but before you checked complete
), but "sometimes two" is better than "sometimes zero." :-)
jQuery's subtly-named one
function can be useful in this context:
function handle_photoloads() {
$(".hphoto").each(function (i,obj) {
var photo = $(obj); // Or = $(this), which would be more common
console.log("Yo");
photo.one("load", function() { // Note `one`, not `on`
photo.css('opacity','1');
});
if (photo.prop("complete")) {
photo.trigger("load");
}
});
}
one
removes the handler the first time it's called. So we only get one callback, regardless of timing.
(In the above, instead of if (photo.prop("complete"))
, you could do if (photo[0].complete)
)
Upvotes: 3