Closure code to assign image index to onload handler

H

howardk

I'm writing some code that loads a number of images, using the
standard mechanism of assigning a src url to a newly constructed Image
object, thus invoking the image-load operation. On a successful load,
an image.onload handler I've previously assigned will be called. Or
should be at any rate.

The problem is that I need to know inside the onload handler which
particular image in the array invoked the handler. I'd be quite happy
to know the array index of the successfully loaded image, but since
onload handler assignments can't take a parameter, I can't assign the
index when I set up the onload call. So I'm a bit stumped.

The answer seems to be to use a closure to supply the index of the
invoking image when I set up the handler, but I'm still struggling a
bit w/ closures and can't seem to be able to get the syntax right. Can
anyone supply a snippet of code to show how to do this?

Any help would be much appreciated!
Thanks,
Howard
 
S

slebetman

I'm writing some code that loads a number of images, using the
standard mechanism of assigning a src url to a newly constructed Image
object, thus invoking the image-load operation. On a successful load,
an image.onload handler I've previously assigned will be called. Or
should be at any rate.

The problem is that I need to know inside the onload handler which
particular image in the array invoked the handler. I'd be quite happy
to know the array index of the successfully loaded image, but since
onload handler assignments can't take a parameter, I can't assign the
index when I set up the onload call. So I'm a bit stumped.

The answer seems to be to use a closure to supply the index of the
invoking image when I set up the handler, but I'm still struggling a
bit w/ closures and can't seem to be able to get the syntax right. Can
anyone supply a snippet of code to show how to do this?

var imgObject = somehowCreateImageObject();
imgObject.src = uriPath;
imgObject.onload = function () {
onloadHandler(imgObject);
}


/*
but remember, you're not passing the value of the variable here,
you're passing the variable itself. So if used in a loop all
the handlers will get the last value of imgObject. But you can
create another closure to pass a reference to that specific
instance of the variable like so:
*/

(function (x) {
imgObject.onload = function () {
onloadHandler(x);
}
})(imgObject); // <-- here you pass a ref to imgObject as x
 
D

David Mark

Should in some browsers.
var imgObject = somehowCreateImageObject();

Now there is a black box.
imgObject.src = uriPath;
imgObject.onload = function () {
  onloadHandler(imgObject);

}

/*
  but remember, you're not passing the value of the variable here,
  you're passing the variable itself. So if used in a loop all

You mean a reference to the image?
  the handlers will get the last value of imgObject. But you can
  create another closure to pass a reference to that specific
  instance of the variable like so:
*/

(function (x) {
  imgObject.onload = function () {
    onloadHandler(x);
  }

})(imgObject); // <-- here you pass a ref to imgObject as x

This will leak memory in IE (and is needlessly complex.)

How about:

imgObject.onload = onloadHandler;

Then refer to the image object as "this".
 
H

howardk

Should in some browsers.





Now there is a black box.


You mean a reference to the image?




This will leak memory in IE (and is needlessly complex.)

How about:

imgObject.onload = onloadHandler;

Then refer to the image object as "this".

Here's what I finally ended up doing, and it seems to work ok:

function imageLoaded( n ) {
return function( ) {
if ( window.console ) {
window.console.log( 'You\' just loaded image# ' + n );
// do stuff with images[ n ] image object
}
}
};

function loadAllImages() {
var image = new Image();
image.onload = imageLoaded(i);
...
}
 
T

Thomas 'PointedEars' Lahn

slebetman said:
var imgObject = somehowCreateImageObject();
imgObject.src = uriPath;
imgObject.onload = function () {
onloadHandler(imgObject);
}

/*
but remember, you're not passing the value of the variable here,
you're passing the variable itself.
Nonsense.

So if used in a loop all
the handlers will get the last value of imgObject.

The reason for that would be late resolution of the variable identifier
instead, supported by the closure that the function expression creates.


PointedEars
 
D

David Mark

Should in some browsers.
Now there is a black box.
You mean a reference to the image?
This will leak memory in IE (and is needlessly complex.)
How about:
imgObject.onload = onloadHandler;
Then refer to the image object as "this".

Here's what I finally ended up doing, and it seems to work ok:

function imageLoaded( n ) {
    return function( ) {
         if ( window.console ) {
             window.console.log( 'You\' just loaded image# ' + n );
             // do stuff with images[ n ] image object
         }
    }

};

function loadAllImages() {
    var image = new Image();
    image.onload = imageLoaded(i);
    ...

}

Why not:

function imageLoaded() {
window.alert(this.src);
}

var image = new Image();
image.onload = imageLoaded;
....

And make sure the Image constructor exists before calling it.
 
T

Thomas 'PointedEars' Lahn

David said:
Here's what I finally ended up doing, and it seems to work ok:

function imageLoaded( n ) {
return function( ) {
if ( window.console ) {
window.console.log( 'You\' just loaded image# ' + n );
// do stuff with images[ n ] image object
}
}

};

function loadAllImages() {
var image = new Image();
image.onload = imageLoaded(i);
...

}

Why not:

function imageLoaded() {
window.alert(this.src);
}

var image = new Image();
image.onload = imageLoaded;
...

Two good reasons:

1. There we have a global method to no obvious advantage.

2. The OP wanted to know the *index* of the image object or data
related thereto in *another* data structure, not its URI.
I would presume something should happen to that image or for it
when it was loaded.

An application that comes to mind, since I have been dealing
with it before, is loading the high-resolution version of an
image when the low-res version has finished loading. To do
that, it doesn't help to know the URI of the low-res image,
you need a reference to the target (HTML)Image(Element) object;
the index of the image object helps to retrieve that.
And make sure the Image constructor exists before calling it.

Full ACK.


PointedEars
 
D

David Mark

David said:
Here's what I finally ended up doing, and it seems to work ok:
function imageLoaded( n ) {
    return function( ) {
         if ( window.console ) {
             window.console.log( 'You\' just loaded image# ' + n );
             // do stuff with images[ n ] image object
         }
    }
};
function loadAllImages() {
    var image = new Image();
    image.onload = imageLoaded(i);
    ...
}
function imageLoaded() {
   window.alert(this.src);
}
var image = new Image();
image.onload = imageLoaded;
...

Two good reasons:

1. There we have a global method to no obvious advantage.

Well, it doesn't have to be global. As written, yes.
2. The OP wanted to know the *index* of the image object or data
   related thereto in *another* data structure, not its URI.
   I would presume something should happen to that image or for it
   when it was loaded.

If he has data stored about the image, then yes that would be a good
case for using the other solution.

[snip]
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,065
Latest member
OrderGreenAcreCBD

Latest Threads

Top