views:

162

answers:

3

I am attempting to collapse a div on request, but my setTimeout function will does not successfully call its callback function. Here is the code below:

 function newsFeed() {

    this.delete = function(listingID) {

     var listing = document.getElementById(listingID);
     var currHeight = listing.offsetHeight;

     var confirmDelete = confirm("Are you sure you'd like to delete this listing forever?");
     if (confirmDelete) {
      this.collapse(listingID,currHeight,currHeight,100);
     }

    }

    this.collapse = function(listingID,orig_height,curr_height,opacity) {
     var listing = document.getElementById(listingID);
     var reduceBy = 10;
     if(curr_height > reduceBy) {
      curr_height = curr_height-reduceBy;
      listing.style.overflow = "hidden";
      listing.style.height = (curr_height-40) + "px";

      if(opacity > 0) {
       opacity = opacity - 10;
       var opaque = (opacity / 100);

       listing.style.opacity=opaque;                      
       listing.style.MozOpacity=opaque;                   
       listing.style.filter='alpha(opacity='+opacity+')';
      }

      setTimeout("this.collapse('"+listingID+"',"+orig_height+","+curr_height+","+opacity+")",1);
     }
    }
}

var newsFeed = new newsFeed();

and I call it in the document as follows:

<div id="closeMe">
    <a onclick="newsFeed.delete('closeMe');">close this div</a>
</div>

When it gets to the setTimeout function within this.collapse ... it errors "this.collapse is not a function".

A: 

When the timeout is called, this is no longer what you want it to be. You'll need to refer to the DOM element you want by some other mechanism, perhaps ID-based retrieval.

chaos
+3  A: 

When the timeout calls you've exited the function and "this" no longer refers to what you think it does.

You should use a closure, like this:

var self = this;
setTimeout(function()
{
    self.collapse(listingID, orig_height, curr_height, opacity);
}, 1);
Greg
do i put this within newsFeed() or within the this.collapse function? aka...is what should 'this' actually be referring to?
johnnietheblack
...sorry, because now im getting self.collapse is not a function
johnnietheblack
got it, you RULE
johnnietheblack
Generally setTimeout should always be used with a function, not a string (which is pretty much the same things as the hated `eval`). For passing values into the function you can either use a dedicated bind-function-to-parameters method, or just put it in an anonymous function like in Greg's example.
bobince
+1  A: 

The behavior that you are seeing is because the scoping issue in JavaScript. JavaScript has just two scopes - function and global.

When you perform a setTimeout() call, you have to set variables in the global scope, if you wish to use that state in the code executed due to the setTimeout() call. That would be the fix to the issue; Greg has already suggested a way to do this.

You'll find more information in the Mozilla Developer Center in the pages about setTimeout and in the Core JavaScript Reference.

Vineet Reynolds