views:

291

answers:

3

I'm having an issue with building a Javascript object, and calling methods within that object using setTimeout. I've tried various workarounds, but always during the second part of my loop the scope becomes the window object rather than my custom object. Warning: I'm pretty new at javascript.

my code:

$(function() {
 slide1 = Object.create(slideItem);
 slide1.setDivs($('#SpotSlideArea'));
 slide1.loc = 'getSpot';
 slide2 = Object.create(slideItem);
 slide2.setDivs($('#ProgSlideArea'));
 slide2.loc = 'getProg';
 slide2.slide = 1;
 setTimeout('triggerSlide(slide1)', slide1.wait);
 setTimeout('triggerSlide(slide2)', slide2.wait);
});

function triggerSlide(slideObject) {
 slideObject.changeSlide(slideObject);
}

var slideItem = {
 div1: null,
 div2: null,
 slide: 0,
 wait: 15000,
 time: 1500,
 loc: null,
 changeSlide: function(self) {
  this.slide ? curDiv = this.div1:curDiv = this.div2;
  $(curDiv).load(location.pathname + "/" + this.loc, this.slideGo(self));
 },
 setDivs: function(div) {
  var subDivs = $(div).children();
  this.div1 = subDivs[0];
  this.div2 = subDivs[1];
 },
 slideGo: function(self) {
  if(this.slide) {
   $(this.div2).animate({
    marginLeft: "-300px"
   }, this.time);
   $(this.div1).animate({
    marginLeft: "0"
   }, this.time);
   setTimeout('triggerSlide(self)', this.wait);
  } else {    
   $(this.div1).animate({
    marginLeft: "300px"
   }, this.time);
   $(this.div2).animate({
    marginLeft: "0"
   }, this.time);
   setTimeout('triggerSlide(self)', this.wait);
  }   
  this.slide ? this.slide=0:this.slide=1;
 }
}

My latest attempt was building the helper function triggerSlide so that I could attempt to pass the reference to the object through my methods, but even that doesn't seem to work.

I could use setInterval and it works, however:

  1. I want to ensure the animation has completed before the timer restarts
  2. I don't learn how to get around the issue that way. :)
A: 

I can't test this code right now, but does this help?

setTimeout(function(){triggerSlide(slide1)}, slide1.wait);
lance
Ugg. Why would you pass that in as a string?
Pointy
As opposed to what? Specifying a function name?
lance
Yes, specifying a function name or an anonymous function. In your example, it'd work just fine to take away the quotes altogether. However, his mechanism is needlessly complex anyway, and it really should be done differently.
Pointy
Ah, right. The anonymous function was my intent. The string was my syntax ignorance. I'll correct it. Hopefully your answer will be more helpful to him.
lance
Cool. We'll see; Javascript is a weird language to get started in - it's both easy and hard at the same time.
Pointy
A: 

This is jQuery, correct? There's a callback parameter to animate(); pass it the function you want called after the animation completes and jQuery will take care of calling it. The callback should capture the scope you want just fine.

kevingessner
+2  A: 
Pointy
+1 code in strings are generally best avoided unless absolutely necessary. That includes `new Function('some code');`, `setTimeout("doSomething()", 0);` and everyone's favourite, `eval('some code');`. The first two of which I've *never* seen a necessity for, the third only for JSON and input math expressions :-)
Andy E
I tried the above, and it works for the initial call, but the calls to repeat the action (the setTimeout() calls in slideGo() still do not work. I formatted them as the above, but utilizing this in place of slideItem above. i.e. setTimeout(function() { this.changeSlide(); }, this.wait);I get an error in Firebug that this.changeSlide() is not a function. I know early in the slideGo method that 'this' is referencing my slideItem, however it doesn't appear to when that second setTimeout call happens. This is where I'm confused.
Shawn Parr
I should also mention that I tried adding that=this in the beginning of my slideGo method, however that seems to get added in a global scope rather than just within the method. I have multiple objects on the page so that makes only one of them animate, triggered by each setTimeout.
Shawn Parr
Well if it's not working then that just means you're not setting things up properly in the calls to "setTimeout". All of them should use something like the anonymous function setup that I described above (assuming that "slideItem" is the context object you actually want to use; it's a little hard for me to tell what's going on.)
Pointy
AAAARRRGH!! In my mad race to power and glory I missed something vital apparently (I know now). JS apparently handles "that = this" differently than "var that = this"The second works perfectly.So my code in slideGo is now setTimeout(function() { that.changeSlide(); }, this.wait);Which means I can probably reduce the number of methods, and move the code in slideGo back into changeSlide to simplify things a bit (I had it like that originally but have been trying to solve this).Thank you Pointy for your excellent explanations.
Shawn Parr
Yaay! I'm glad to hear that you're making progress! Yes, if you do an assignment to a variable in a function, and you leave off "var", you're actually creating a global variable!! It's a really easy mistake to make until you get used to typing "var" all the time.
Pointy