0

This is some JavaScript I have for a simple navigation bar but I have issues with the drop down disappearing before you can click on them so I want to add a delay after the mouse leaves the bar before they hide.

How would I do that?

<script type="text/javascript">
    $(document).ready(function () {
        // Navigation bar drop-down
        $("nav ul li").hover(function () {
            $(this).addClass("active");
            $(this).find("ul").show().animate({ opacity: 1 }, 400);
        }, function () {
            // Delay on hiding should go here
            $(this).find("ul").hide().animate({ opacity: 0 }, 200);
            $(this).removeClass("active");
        });
        $('nav ul li ul li:first-child').prepend('<li class="arrow"></li>');
        $('nav ul li:first-child').addClass('first');
        $('nav ul li:last-child').addClass('last');
        $('nav ul li ul').parent().append('<span class="dropdown"></span>').addClass('drop');
    });
</script>

Thanks in advance to anyone who can help

P.S. This is probably really obvious but I know very little about JavaScript. :L

Pointy
  • 405,095
  • 59
  • 585
  • 614

6 Answers6

3

I have a simple navigation bar

Don't use JavaScript then. This can and should be done with CSS. CSS transitions and selectors allow to define exactly what you want.

See also Delay :Hover in CSS3? and the excellent example from there.

Community
  • 1
  • 1
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
2

Don't use a huge function such as delay(). Just use setTimeout().

var that = this
setTimeout(function() {
    $(that).hide() // Do your stuff, just don't forget that "this" has changed
}, 1000) // Define your delay in milliseconds here

The function inside the setTimeout will execute after the delay specified as a second argument.

Florian Margaine
  • 58,730
  • 15
  • 91
  • 116
  • delay() is not really a huge function. It pops your anonymous function onto a queue stack, calls it through setTimeout(), and returns a jQuery object. You're not looking at any sort of performance hit, since obviously you're not going to be running delay in a loop anyway. – Jordan Apr 09 '12 at 18:35
2

You can do it like this. You use the delay() method to set up the delay and you use .stop(true) on both hover functions in case the user goes out and comes back in during the delay. The .stop(true) will clear any queued animations. I also switched the code to fadeIn() and fadeOut() because those automatically do the show() and hide() as needed.

<script type="text/javascript">
    $(document).ready(function () {
        // Navigation bar drop-down
        $("nav ul li").hover(function () {
            $(this).addClass("active");
            $(this).find("ul").stop(true).fadeIn(400);
        }, function () {
            // Delay on hiding should go here
            var self = $(this);
            self.find("ul").stop(true).delay(1500).fadeOut(400, function() {
                self.removeClass("active");
            });
        });
        $('nav ul li ul li:first-child').prepend('<li class="arrow"></li>');
        $('nav ul li:first-child').addClass('first');
        $('nav ul li:last-child').addClass('last');
        $('nav ul li ul').parent().append('<span class="dropdown"></span>').addClass('drop');
    });
</script>
jfriend00
  • 683,504
  • 96
  • 985
  • 979
1

I think you can do something like this:

<script type="text/javascript">
    $(document).ready(function () {
        // Navigation bar drop-down
        $("nav ul li").hover(function () {
            $(this).addClass("active");
            $(this).find("ul").show().animate({ opacity: 1 }, 400);
        }, function () {
            // Delay on hiding should go here
            $(this).find("ul").hide().delay(1000).animate({ opacity: 0 }, 200, function() {
                $(this).removeClass("active");
            });  
        });
        $('nav ul li ul li:first-child').prepend('<li class="arrow"></li>');
        $('nav ul li:first-child').addClass('first');
        $('nav ul li:last-child').addClass('last');
        $('nav ul li ul').parent().append('<span class="dropdown"></span>').addClass('drop');
    });
</script>
MilkyWayJoe
  • 9,082
  • 2
  • 38
  • 53
  • The `.removeClass()` won't properly here because `this` will be the nested `ul`, not the `li` that it was in the OP's code. In addition, I think you have to properly handle the case where the mouse goes out and then comes back in during the delay. – jfriend00 Apr 09 '12 at 18:02
1

You could use delay().

<script type="text/javascript">
    $(document).ready(function () {
        // Navigation bar drop-down
        $("nav ul li").hover(function () {
            $(this).addClass("active");
            $(this).find("ul").show().animate({ opacity: 1 }, 400);
        }, function () {
            // Delay on hiding should go here
        $(this).find("ul").delay(5000).fadeOut();
            $(this).removeClass("active");
        });
        $('nav ul li ul li:first-child').prepend('<li class="arrow"></li>');
        $('nav ul li:first-child').addClass('first');
        $('nav ul li:last-child').addClass('last');
        $('nav ul li ul').parent().append('<span class="dropdown"></span>').addClass('drop');
    });

</script>
Daniel Cumings
  • 863
  • 8
  • 14
1

Very interesting. Nothing hides, until you mouseout. FIDDLE

Nikita Shekhov
  • 493
  • 3
  • 11