49

I have a drop down menu. Now when it's slided down to multiple levels, I'd like it to add wait time for like 2 secs, before it disappears, so the user can get back in, when he breaks the .hover() by mistake.

Is it possible?

my code for the slide:

$('.icon').hover(function() {
        $('li.icon > ul').slideDown('fast');
    }, function() { 
        $('li.icon > ul').slideUp('fast');
    });
user3708642
  • 124
  • 10

9 Answers9

75

This will make the second function wait 2 seconds (2000 milliseconds) before executing:

$('.icon').hover(function() {
    clearTimeout($(this).data('timeout'));
    $('li.icon > ul').slideDown('fast');
}, function() {
    var t = setTimeout(function() {
        $('li.icon > ul').slideUp('fast');
    }, 2000);
    $(this).data('timeout', t);
});

It also clears the timeout when the user hovers back in to avoid crazy behavior.

This is not a very elegant way of doing this, however. You should probably check out the hoverIntent plugin, which is designed to solve this particular problem.

Paolo Bergantino
  • 480,997
  • 81
  • 517
  • 436
  • This should be the 1st answer. – Ronan Oct 11 '13 at 10:26
  • 1
    Hi. I am trying the same in [this jsFiddle](http://jsfiddle.net/GZV5V/85/) for `slideDown()` and `slideUp()`, but `slideUp()` doesn't work well. Can you please tell me what am I missing here? Note: I am trying to do it without using `hoverIntent()` function. – Himanshu Nov 13 '13 at 05:26
  • @him056 you had a scope problem in your jsFiddle. It works here http://jsfiddle.net/671noauq/ – Adam Feb 12 '16 at 17:18
  • jquery plugins dont play nice in typescript, so this is the way for me. – StingyJack Mar 29 '17 at 12:08
43

personally I like the "hoverIntent" plugin:

http://cherne.net/brian/resources/jquery.hoverIntent.html

from the page: hoverIntent is a plug-in that attempts to determine the user's intent... like a crystal ball, only with mouse movement! It works like (and was derived from) jQuery's built-in hover. However, instead of immediately calling the onMouseOver function, it waits until the user's mouse slows down enough before making the call.

Why? To delay or prevent the accidental firing of animations or ajax calls. Simple timeouts work for small areas, but if your target area is large it may execute regardless of intent.

var config = {    
 sensitivity: 3, // number = sensitivity threshold (must be 1 or higher)    
 interval: 200, // number = milliseconds for onMouseOver polling interval    
 over: makeTall, // function = onMouseOver callback (REQUIRED)    
 timeout: 500, // number = milliseconds delay before onMouseOut    
 out: makeShort // function = onMouseOut callback (REQUIRED)
};
$("#demo3 li").hoverIntent( config ) 

Configuration Options

sensitivity: If the mouse travels fewer than this number of pixels between polling intervals, then the "over" function will be called. With the minimum sensitivity threshold of 1, the mouse must not move between polling intervals. With higher sensitivity thresholds you are more likely to receive a false positive. Default sensitivity: 7

interval: The number of milliseconds hoverIntent waits between reading/comparing mouse coordinates. When the user's mouse first enters the element its coordinates are recorded. The soonest the "over" function can be called is after a single polling interval. Setting the polling interval higher will increase the delay before the first possible "over" call, but also increases the time to the next point of comparison. Default interval: 100

over: Required. The function you'd like to call onMouseOver. Your function receives the same "this" and "event" objects as it would from jQuery's hover method.

timeout: A simple delay, in milliseconds, before the "out" function is called. If the user mouses back over the element before the timeout has expired the "out" function will not be called (nor will the "over" function be called). This is primarily to protect against sloppy/human mousing trajectories that temporarily (and unintentionally) take the user off of the target element... giving them time to return. Default timeout: 0

out: Required. The function you'd like to call onMouseOut. Your function receives the same "this" and "event" objects as it would from jQuery's hover method. Note, hoverIntent will only call the "out" function if the "over" function has been called on that same run.

SavoryBytes
  • 35,571
  • 4
  • 52
  • 61
  • I used this for many years until I realize its a **overkill** for cases like the question. The manual code examples in this thread working fine. – Jonas Lundman Oct 18 '17 at 06:27
1

The general idea is to use setTimeout, like so:

$('.icon').hover(function() {
           $('li.icon > ul').slideDown('fast');
    }, function() { 
           setTimeout(function() {
                $('li.icon > ul').slideUp('fast');
           }, 2000);
    });

But this may do counterintuitive things if the user mouses out and then mouses in again quickly—this doesn't account for clearing the timeout when the user hovers over it again. That would require additional state.

John Calsbeek
  • 35,947
  • 7
  • 94
  • 101
1

or you could simply use transition:all 2s ease-in-out. make sure that you add -webkit, -moz and -o for different browsers.

yklee1013
  • 11
  • 1
1
$('.icon').on("mouseenter mouseleave","li.icon > ul",function(e){
   var $this = $(this);
   if (e.type === 'mouseenter') {
       clearTimeout( $this.data('timeout') );
       $this.slideDown('fast');
   }else{ // is mouseleave:
       $this.data( 'timeout', setTimeout(function(){
           $this.slideUp('fast');
       },2000) );  
   }
 });
Roko C. Buljan
  • 196,159
  • 39
  • 305
  • 313
gustav
  • 91
  • 6
1

The following will stop the sliding from triggering by 2 seconds:

$('.icon').hover(function() {
  $('li.icon > ul').delay(2000).slideDown('fast');
}, function() { 
  $('li.icon > ul').slideUp('fast');
});
Dan Atkinson
  • 11,391
  • 14
  • 81
  • 114
Steph
  • 635
  • 7
  • 22
  • I think this achieves basically the opposite: The hover action isn't triggered immediately, but it's necessary to hover for at least 2 seconds for anything to happen. Still useful, but not exactly an answer to the question. Am I wrong? – Simon Steinberger Nov 07 '15 at 21:58
0

I think this is code your need:

    jQuery( document ).ready( function($) {  
    var navTimers = [];  
    $('.icon').hover(function() { 
            var id = jQuery.data( this );  
            var $this = $( this );  
            navTimers[id] = setTimeout( function() {  
                $this.children( 'ul' ).slideDown('fast');  
                navTimers[id] = "";  
            }, 300 );  
        },  
        function () {  
            var id = jQuery.data( this );  
            if ( navTimers[id] != "" ) {  
                clearTimeout( navTimers[id] );  
            } else {  
                $( this ).children( "ul" ).slideUp('fast'); 
            }  
        }  
    );  
}); 
Sakata Gintoki
  • 1,817
  • 16
  • 23
0

I would like to add to Paolo Bergantino that you can do this without the data attribut:

var timer;
$('.icon').hover(function() {
    clearTimeout(timer);
    $('li.icon > ul').slideDown('fast');
}, function() {
    timer = setTimeout(function() {
        $('li.icon > ul').slideUp('fast');
    }, 2000);
});
bbonamin
  • 30,042
  • 7
  • 40
  • 49
Adam
  • 25,960
  • 22
  • 158
  • 247
0
var timer;

var delay = 200;

$('#hoverelement').hover(function() {

    on mouse hover, start a timeout

    timer = setTimeout(function() {

       Do your stuff here 

    }, delay);

}, function() {

   Do mouse leaving function stuff here    

    clearTimeout(timer);
});

//edit: instert code

Hadnazzar
  • 1,517
  • 19
  • 21