views:

137

answers:

1

I would like to have a pulldown menu close itself upon a mouseleave event, after a short delay. But I'm having trouble getting it working.

Consider the following methods in an object: (I am using jQuery)

myObj = {};

myObj.message = "woot!";

myObj.bindEvents = function() {

        var that = this;

        $("#menuPanel")
            .bind("mouseleave", function() { 

                    that.timer = setTimeout(that.closeMenu,500); 

            });

    }

myObj.closeMenu = function() {

     // close the menu

     alert(this.message);

}

This doesn't work. That is to say, this.message comes up undefined. After a bit of digging, I understand why. :) The 'that' reference is not available to code inside of setTimeout at the time of execution.

I'm wondering, what is the "best" way to get around this type of problem? How can I have a method that uses setTimeout call another method in the same object, and still have access to the properties in the object?

Thanks in advance for your help.

+1  A: 

The problem here is that you're detaching the closeMenu method from it's object you would have the same problem if you did this:

var closeMenu = myObj.closeMenu;  // detaching the method from the object
closeMenu();

Detaching and calling methods like this means they no longer apply to the objects they were created on. In your example, you're doing almost the same thing:

// Setting the first parameter of setTimeout to be the detached closeMenu method
that.timer = setTimeout(that.closeMenu,500); 

A fix for the first method would be to use the call or apply methods:

var closeMenu = myObj.closeMenu;  // detaching the method from the object
closeMenu.apply(myObj);

But that wouldn't work for a timer. Instead, create an anonymous function:

that.timer = setTimeout(function () { that.closeMenu(); },500); 


It might also be worth mentioning bind() - not to be confused with jQuery's $('#selector').bind() - a method that's been floating around on various blogs and in some libraries (Prototype being the most notable) for a while now, and has finally been implemented in ECMAScript edition 5.

that.timer = setTimeout(that.closeMenu.bind(that),500);

I use a similar method in one or two classes I created, because it just makes things easier.

Andy E
awesome. thank-you!
Travis
@Travis: no worries. I added a little more about the `bind()` method in ECMAScript 5th Edition about 11 seconds after you posted that comment, might be useful to you :-)
Andy E
And another -1 with no explanation. I think I might have a stalker :-)
Andy E