2

I tried this js code:

<script type="text/javascript">

       $(document).ready( function() {
            var timer;
            $('.top-menu-first-ul li').hover(function(){
                        if(timer) {
                                clearTimeout(timer);
                                timer = null
                        }
                        timer = setTimeout(function() {
                                   $(this).find('ul').slideToggle(100);
                        }, 500)
            },
            // mouse out
            });
        });


</script>

with this html:

<ul class="top-menu-first-ul">
    <li>
        <a href="http://google.com">Google</a>
        <ul class="top-menu-second-ul">
            <li><a href="http://translate.google.com">Google Translate</a></li>
            <li><a href="http://images.google.com">Google Images</a></li>
            <li><a href="http://gmail.google.com">Gmail</a></li>
            <li><a href="http://plus.google.com">Google Plus</a></li>
        </ul>
    </li>
    <li>
        <a href="http://facebook.com">Facebook</a>
    </li>
    <li>
        <a href="http://twitter.com">Twitter</a>
    </li>
</ul>

but it is not working.

I would like to show the submenu when hovering over e.g. Google link and other will appear after 300ms.

So, I need to prevent loading submenu when the user just quickly hover over it and not stay on hover link for at least 300ms.

Then I need to stop executing code (or slide up) when he leaves the link. Because if he go over and back and over and back a copule of times he stop doing hovering anfd the code is still executing itself how many times he had hover over the link. I need somehow prevent this to happen.

EDIT: I need to solve this without plugins like hoverIntent etc. if possible, just plain javascript and jQuery

Derfder
  • 3,204
  • 11
  • 50
  • 85

2 Answers2

6

Use stop() to prevent animation weirdness and delay() to wait 300ms. Also hover() is deprecated I would suggest using on() instead:

$('.top-menu-first-ul li').on({
  mouseover: function() {
    $(this).find('ul').stop(1,1).delay(300).slideDown(100);
  },
  mouseleave: function() {
    $(this).find('ul').stop(1,1).slideUp(100);
  }
});

Demo: http://jsfiddle.net/elclanrs/6dtWz/

elclanrs
  • 92,861
  • 21
  • 134
  • 171
  • Thanks, but as soon as I leave the Google and want to hover over submenu items like Google translate, Google mail etc. they disappear. Can you fix it? – Derfder Sep 08 '12 at 22:22
  • Yeah just change `mouseout` with `mouseleave`. Check demo again. – elclanrs Sep 08 '12 at 22:31
  • Thanks, at first your updated version was not working too, but than I noticed that if I switch on jsfiddle your demo to jquery 1.6 it will not work. So, I have upragded my jQuery from 1.6.2 version to the latest 1.8.1 and it is working great ;). Thanks. – Derfder Sep 09 '12 at 06:47
  • I was too quick. It do not works in Chrome ;(. It gives me Unexpected token error. – Derfder Sep 09 '12 at 07:11
  • In Opera it works great, but not in Chrome, IE, Firefox ;(. This is weird. I have restarted WAMP, computer etc. but nothings helps. I am running jQuery 1.8.1. This is weird. Why OPera yes and Firefox and Chrome not ? – Derfder Sep 09 '12 at 08:12
  • In Chrome for example it gives me this JS error, when I try to use your code in a new file without anything else: SyntaxError: Unexpected token ILLEGAL – Derfder Sep 09 '12 at 08:16
  • stupid question, but did you reference correct jQuery version? :) And on which line you get the error? – Goran Obradovic Sep 09 '12 at 08:27
  • yes, jquery-1.8.1.min.js. The last line after mouseleave. So, maybe the syntax is wrong. – Derfder Sep 09 '12 at 08:58
  • maybe it is because of jsfiddle http://stackoverflow.com/questions/5733275/chrome-uncaught-syntax-error-unexpected-token-illegal – Derfder Sep 09 '12 at 09:02
  • exactly, stupid jsfiddle ;(. Nw from jsbin it is working without errors. Thanks. – Derfder Sep 09 '12 at 09:04
3

I think that problem is that you use $(this) inside your function which is called in timeout. $(this) inside this closure is not the same as outside (inside jQuery event handler where jQuery sets it for you). Here (jsfiddle) is the solution:

$(document).ready( function() {
            $('.top-menu-first-ul li').mouseenter(mouseIn);
            $('.top-menu-first-ul li').mouseout(mouseOut);
});
function mouseIn(e){
    var target = $(this);
    var timer = setTimeout(function() {
                   target.find('ul').slideDown(100);
        }, 500);
    target.attr("data-timer", timer);
}

function mouseOut(e){
    var target = $(this);
    var timer = target.attr("data-timer");
    if(timer){
        clearTimeout(timer);
    }
    target.find('ul').slideUp(100)
}
​

UPDATE This solution is based on yours, but I suggest to use @elclanrs's solution, as it is better (more readable, uses jQuery API which is intended for this).

Goran Obradovic
  • 8,951
  • 9
  • 50
  • 79