2

I'm very new to JavaScript and jQuery and I'm having trouble with a bit of code.

HTML:

<div class="toggle" style="display: block; width: 200px; height: 200px; background-color: red;">test</div>

JavaScript:

jQuery(document).ready(
    function()
    {
        jQuery(".toggle").on("click", function() {
            console.log("let the toggling begin!");

            jQuery(this).slideToggle(600, function(){ // slide up
                setTimeout(function(){ // wait 4 sec, then slide back down
                    jQuery(this).slideToggle(600)
                }, 4000);
            });
        });
    }
);

So the idea is that you click on the div, it slides up, then 4 seconds later slides back down. It doesn't work.

JSFIDDLE: http://jsfiddle.net/zEqN9/2/

However, if I change the this inside each of the closures to ".toggle", then it does work.

JSFIDDLE: http://jsfiddle.net/YZxMb/

So clearly the issue is my use of this.

I tried passing this as a parameter into each of the two closure functions, but that gave the error Unexpected token this.

How can I access the this variable from the inner functions?

Nate
  • 26,164
  • 34
  • 130
  • 214
  • 1
    Using "this" in a callback is a question that was probably asked 10000 times. – Virus721 Sep 04 '13 at 13:18
  • @Virus721 - I did several searches and read many of the related questions before submitting my question, but perhaps I used the wrong terminology when searching.. – Nate Sep 04 '13 at 13:22
  • 1
    This is a common gotcha as it's meaning is defined at execution time and can change depending on how a function has been called. There is a detailed discussion here: http://stackoverflow.com/questions/3127429/javascript-this-keyword – morechilli Sep 04 '13 at 13:26
  • 2
    Note that `jQuery(this).slideToggle(600).delay(4000).slideToggle(600);` will achieve the effect you're after in a way that is a lot easier to write and read. (Not that it's a bad idea to learn how to deal with the `this` issue, since there are other cases where you definitely need to know about that.) – nnnnnn Sep 04 '13 at 13:28

6 Answers6

4

Create a reference to this in slideToggle function.

 jQuery(document).ready(
    function()
    {
        jQuery(".toggle").on("click", function() {
            console.log("let the toggling begin!");

            jQuery(this).slideToggle(600, function(){ // slide up
                var self = this; // <-- notice this
                setTimeout(function(){ // wait 4 sec, then slide back down
                    jQuery(self).slideToggle(600)
                }, 4000);
            });
        });
    }
);
Ian Brindley
  • 2,197
  • 1
  • 19
  • 28
1

Use bind to specify a this for a function you expect to call out of context.

var foo = {
    bar: function () {
        setTimeout(function () { // though in a setTimeout
            console.log(this);
        }.bind(this), 0); // binding to `this` here means
    }
};

foo.bar(); // invoking it still has `this` of `foo`
Paul S.
  • 64,864
  • 9
  • 122
  • 138
0

The reason is that for a jQuery event, the context of the function is explicitly set so that this refers to the target element - this is done for you by jQuery. However, the anonymous function for setTimeout doesn't have that context set for you - it gets the default global context, so this refers to the window.

What you need to do is grab a reference to the click event's context, and then use the reference in the timeout:

jQuery(function () {
    jQuery(".toggle").on("click", function () {
        var $this = $(this);

        $this.slideToggle(600, function () { // slide up
            setTimeout(function () { // wait 4 sec, then slide back down
                $this.slideToggle(600);
            }, 4000);
        });
    });
});

However, as pointed out in a comment, this could be written as:

jQuery(function () {
    jQuery(".toggle").click(function () {
        jQuery(this).slideToggle(600).delay(4000).slideToggle(600);
    });
});
cmbuckley
  • 40,217
  • 9
  • 77
  • 91
0
var yourThing = jQuery(this);

yourThing.slideToggle(600, function(){ // slide up
     setTimeout(function(){ // wait 4 sec, then slide back down
          yourThing.slideToggle(600)
     }, 4000);
});
user2722002
  • 65
  • 1
  • 6
0

Just add this line in your code to understand why:

setTimeout(function(){ // wait 4 sec, then slide back down
      console.log(jQuery(this)); //this one
      jQuery(this).slideToggle(600)
      }, 4000);

Open your console. You will see that, in the setTimeout function, $(this) refers to the window object.

TCHdvlp
  • 1,334
  • 1
  • 9
  • 15
0

You need a create a referente to this,so when runs the function associate to setTimeout you can pass this reference.

 jQuery(document).ready(
        function()
        {
            jQuery(".toggle").on("click", function() {
                console.log("let the toggling begin!");
                var that = this; // <--- reference to this
                jQuery(this).slideToggle(600, function(){ // slide up
                    setTimeout(function(){ // wait 4 sec, then slide back down
                        jQuery(that).slideToggle(600)
                    }, 4000);
                });
            });
        }
    );
saeta
  • 4,048
  • 2
  • 31
  • 48