views:

34

answers:

2

I want to add a setTimeout to the following code so that there's a short pause before the fadeOut effect executes.

$(document).ready(function() {  
    $('#menu li').hover(
        function() {
            $('ul', this).slideDown(50);
        }, 
        function() {
            $('ul', this).fadeOut(100);
        }
    );
});

This is what I'm trying, but I'm guessing the syntax must be wrong:

$(document).ready(function() {  
    $('#menu li').hover(
        function() {
            $('ul', this).slideDown(50);
        },
        function() {
            setTimeout(function() {
                $('ul,' this).fadeOut(100);
            });
        }
    );
});

Sorry if this is a dumb question. I'm a beginner with jQuery.

A: 

You could also need to clear the timeout when going over it using clearTimeout() (in case you hover in/out fast), something like this would work:

$(function() {  
  $('#menu li').hover(function() {
    clearTimeout($.data(this, 'timer'));
    $('ul', this).slideDown(50);
  }, function() {
    $.data(this, 'timer', setTimeout($.proxy(function() {
      $('ul,' this).fadeOut(100);
    }, this), 400));
  });
});

This stores/retrieves the timer ID using $.data(), and currently has a 400ms delay, just adjust accordingly.

Nick Craver
This works! Thanks!
Tom
Is there an opposite of "this"? Might there be a way to fadeOut all other ul's when the one you're on is on slideDown?
Tom
@Tom - You can use `.not()` for example: `$('#menu li').not(this).find('ul')` to get all other child `<ul>` elements.
Nick Craver
Thanks, Nick. I had to add some classes to differentiate between the different levels of ul's and li's, but that worked for me. Thanks again!
Tom
@Tom - Welcome :) You can also do `$(this).children('ul')` to go one a level down instead of `$('ul', this)`, if that helps any :)
Nick Craver
To clarify, I had to add identifying classes to prevent the 2nd level ul's from disappearing prematurely. Otherwise, they'd disappear as soon as I mouseout from the top level li. $(this).children('ul') doesn't seem to solve that, unless I'm doing it wrong:$(document).ready(function() { $('#menu li').hover(function() { clearTimeout($.data(this, 'timer')); $(this).children('ul').slideDown(50); $('#menu li').not(this).children('ul').hide(); }, function() { $.data(this, 'timer', setTimeout($.proxy(function() { $(this).children('ul').fadeOut(100); }, this), 500)); });});
Tom
+2  A: 

The meaning of this is different within a setTimeout(). You need to reference the desired this in a variable or get the ul first and reference that.

var th = this;
setTimeout(function() {
    $('ul', th).fadeOut(100);
});

or

var $ul = $('ul',this);
setTimeout(function() {
    $ul.fadeOut(100);
});
patrick dw
+1 - Good catch on this, `$.proxy()` is also an alternative here to maintain context.
Nick Craver
@Nick - Thanks. Why do I *always* forget about `$.proxy()`?!
patrick dw