0

I am having trouble getting the following setTimeouts to work:

$('a').click(function(){
    if( last ) {
        if( ($(this).attr('id') == last.attr('id')) ) {
            setTimeout( function(){ 
                $(this).parent().parent().css('visibility','hidden'); 
            },500); 
            setTimeout( function(){ 
                last.parent().parent().css('visibility','hidden'); 
            },500); 
            found++; 
        } 
        if (found == 3) { 
            alert('You won a sticker!'); 
            window.location.href = "#play2"; 
            location.reload(); //resets found to 0 
        } last = null; 
    } 
    else { 
        last = $(this) 
    } 
});

The functions inside the setTimeout work so that it not the problem. I am wondering if there is something wrong with my syntax. I can't find anything wrong with it, however.

0

4 Answers 4

3

In the first setTimeout this === window. You'd probably want to create a closure

var that = this
setTimeout( function(){
    $(that).parent().parent().css('visibility','hidden');
 },500);
Sign up to request clarification or add additional context in comments.

Comments

1

It's not a problem with the setTimeout() syntax. The problem is that within a function this is set depending on how that function is called, and when you call your function via setTimeout() then this is no longer the DOM element from your click event. You can keep a reference to it outside the function you pass to setTimeout(), which could also save you selecting $(this) twice (if you use the saved reference both in your function and in the if statement). I don't see anything wrong with the second setTimeout() since it already uses a reference from outside the function.

    var $this = $(this);
    if( ($this.attr('id') == last.attr('id')) ) {
        setTimeout( function(){ 
            $this.parent().parent().css('visibility','hidden'); 
        },500); 
        setTimeout( function(){ 
            last.parent().parent().css('visibility','hidden'); 
        },500); 
        found++; 
    }

Alternatively if you use .hide() then you can use jQuery's animation queue to .delay() things rather than setTimeout():

    $(this).parent().parent().delay(500).hide(1);

Makes for neater code, but .hide() will set display:none rather than visibility:hidden and I acknowledge that that might not be what you want (you can't use .delay() with .css() because .css() is not an animation method).

Comments

1

The value of this inside the click handler is a reference to the element that was clicked. The value of this inside the callback to setTimeout is the global window object. The key point is that the value of this inside a function is contextual (i.e. it is dependant on how the function was invoked).

You need to save a reference to the value of this from the outer scope so that you can use it inside the inner scope:

if ($(this).attr('id') == last.attr('id')) {
    var that = $(this);
    setTimeout( function() { 
        that.parent().parent().css('visibility','hidden'); 
    },500); 
    // ...
}

Comments

0

Using jQuery idioms:

setTimeout(jQuery.proxy(function(){
  $(this).parent().parent().css('visibility','hidden');
}, this), 500);

Standard JavaScript:

setTimeout(function(){
  $(this).parent().parent().css('visibility','hidden');
}.bind(this), 500);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.