johnnietheblack
johnnietheblack

Reputation: 13320

Why does this setTimeout callback give me an error?

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".

Upvotes: 1

Views: 554

Answers (3)

Vineet Reynolds
Vineet Reynolds

Reputation: 76709

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.

Upvotes: 1

Greg
Greg

Reputation: 321598

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);

Upvotes: 3

chaos
chaos

Reputation: 124287

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.

Upvotes: 0

Related Questions