View Full Version : setTimeout("this.function") passing instance method

12-16-2004, 07:37 PM
I'm using setTimeout() to animate an image moving across the screen to the edge of the page. When I call setTimeout() and pass it a this.function as the function to execute it won't do it & throws and err saying it's not a function. I've also tried passing a reference to an object and it didn't seem to like that either.

I've extended the Image class adding several prototype methods and proerties of my own. I wanted to call the Image instance's animateLeft method repeatedly & delayed so that it looks as though the image moves across the screen to the edge.

the _P functions are used to extend the Image object and they become the instance methods sans '_p' : animateLeft_p() can then be called using "this.animateLeft()"

Here's the code:

// Params that control the speed images animate left and up
var moveIncr = 1;
var timeInt = 10;

//instance method of Image to animate the image to the left edge of screen
function animateLeft_p()
this.lcounter = 1;
this.startX = this.getLeft();
this.movedSum = 0;

while(this.startX - this.movedSum > 0)
this.movedSum = this.movedSum + moveIncr;
///************Below is the problem call *************
this.lcounter =this.lcounter+1;
function moveLeft_p(pxls)
this.style.left=parseInt(this.style.left) - pxls;
function getLeft_p()
return parseInt(this.style.left);

//add the methods & properties to each subsequent image object created
// so I can call using someImage.animateLeft() for example
Image.prototype.animateLeft = animateLeft_p;
Image.prototype.moveLeft = moveLeft_p;
Image.prototype.getLeft = getLeft_p;
Image.prototype.lcounter = 1;
Image.prototype.movedSum = 0;
Image.prototype.startX = null;

//Now create the image objects
projects = new Image(100,100);
projects.src = "http://www.bytality.com/prog_arch/images/projects_100x100.jpg";

Here's the HTML code:

<IMG src="images/blue_logo_100x100.jpg" style="position:absolute;left:100;top:0;" height="100" id="bluelogo" width="100" onclick="this.animateLeft();">

I had been using public vars to do this, and that worked for a single image, but when I move multiple images at once, they share the control variables and don't move the entire distance correctly.

Anyone know how I can make the code work using setTimeout() function or another function?

12-16-2004, 08:19 PM
You'd need to use a global object reference in an anonymous function, because setTimeout is not local.

As in: setTimeout(function(){//object.method(arg); etc...}, milliseconds);

Well, sort of, because local variables can be used, but the function itself is seperate, so "this" is in a different context--I meant.

12-16-2004, 09:05 PM
Yeah, but when I use a global var and move multiple images, they simultaneously share that global var and they don't move correctly.

More than one starts modifying the control vars at the same time and the math goes haywire.

Is there some why I can pass the string name without using a global var?

12-16-2004, 09:19 PM
The problem is that setTimeout and setInterval are not local methods of your object, they're methods of the window, therefore "this" inside a timer is a reference to window.

But there is a little trick you can do - create a scope-global reference to "this" inside the constructor, which you'll then be able to refer to from inner functions. This kind of thing:

//some object constructor
function someObjectConstructor()
//create a test variable
this.test = 'hello world';

//create a global [within this scope] reference to this
var self = this;

//start an anonymous timer
this.timer = window.setInterval(function()

alert(self.test); //"hello world"
alert(self.timer); //a reference to this timer

}, 5000);

12-16-2004, 09:32 PM
Things can be kept seperate when assigned as object properties. Each new call could check for a pre-existing prop, create a new one if not found, or modify the cycle accordingly.

That was not to discount the above point, btw... ;)

12-18-2004, 02:19 AM
That was not to discount the above point, btw... ;)
It doesn't :) The principle is the same with what I suggested, except you haven't had to pollute the global scope with another variable :thumbsup:

12-18-2004, 05:55 AM
Actually, I had something else in mind when mentioning that, but it was sort of a tangent, I guess, looking back... :p

12-18-2004, 03:25 PM
Things can be kept seperate when assigned as object properties. Each new call could check for a pre-existing prop, create a new one if not found, or modify the cycle accordingly.

That was not to discount the above point, btw... ;)

I tried using an object property, except I still couldn't figure out a way to pass the particular object without storing to a global var for use with setTimeout(). You can't use a this reference at all and any time I use a global, multiple images will be moving at once and they share the global var and it screws everything up!

How come my prototyped custom object properties aren't seeming to be protected within the Image object? Does that just add a reference to the global function rather than nesting it within the object for var protection, or didn't I do it right?

Using brothercake's hint, I tried creating an new image_wrapper() object that created an internal image object when the wrapper object was constructed. That way I could add the object.self reference to my custom object rather than extending the standard Image object. My problem there came in using the image_wrapper for calling. I couldn't call Image.moveLeft() from the HTML because the functions are now owned by the image_wrapper object not the image object which meant I couldn't use 'this' in the moveLeft() to move the image. How can I associate the HTML image with my image_wrapper object instead of a standard Image object? If I could do that it may work with some tweaking.... maybe.

Does that make sense to anyone?

12-18-2004, 06:16 PM
I dunno. :D
A prototype for Image is undefined in IE, btw.

Here's how I might set that type o' thing up...

<script type="text/javascript">

var active = [];

function animateLeft(elem, indx)
if(typeof active[indx] != "undefined")
var moveIncr = 5;
var startX = parseInt(elem.style.left);
(function moveLeft()
if((startX -= moveIncr) >= 0)
elem.style.left = startX + "px";
active[indx] = setTimeout(moveLeft, 10);
elem.style.left = "0px";

<IMG src="images/blue_logo_100x100.jpg" style="position:absolute;left:100;top:0;" onclick="animateLeft(this, 0);">
<IMG src="images/red_logo_100x100.jpg" style="position:absolute;left:100;top:101;" onclick="animateLeft(this, 1);">
<!-- etc. -->