0

I've got a simple script that opens submenus as you mouse over parent menu items, and it works well. Now I'm just trying to add a timeout, to very slightly delay the opening of the submenus. I've been trying setTimeout, from all sorts of examples and the jquery documentation, but can't get it to work.

Here's the script:

<script type="text/javascript">

$(document).ready (function() {

    $('.xxxMenu > li').on('mouseover', openSubMenu);
    $('.xxxMenu > li').on('mouseout', closeSubMenu);

    function openSubMenu() {
        $(this).find('ul').css('visibility', 'visible');    
    };

    function closeSubMenu() {
        $(this).find('ul').css('visibility', 'hidden'); 
    };



   });
</script>

Here's the HTML, simplified:

<ul class="xxxMenu">
  <li><a href="#">Top Title</a>
    <ul>
      <li><a href="http://blahblah">Title One</a></li>
      <li><a href="http://blahblah">Title Two</a></li>
    </ul>
  </li>
</ul>

As you mouse over "Top Title", a submenu containing "Title One" and "Title Two" drops down. The actual html contains much longer unordered lists.

Can anyone describe where 'setTimeout' would go in order to delay the 'openSubmenu' function?

UPDATE

Thanks for the quick responses, the two answers look excellent. Unfortunately there's a wrinkle in that I'm actually doing all this in a Confluence page, inserted into an "HTML Include" macro, which lets you use HTML in the WIKI page. It's got a few quirks though, one being that I can (and have to) place scripts and CSS directly into the page, there's no head or body involved (there is a head for the whole site, but in areas of the Confluence installation that I don't have permission to edit - long story).

The result is that I haven't been able to get show/hide to work at all, nor either of the solutions below, even though they clearly work in a regular HTML page. Most jquery that I try works, with rare exceptions, but that seems to be one of them.

I have however used animate to get what I need here, partially anyway, based on the suggestion from DinoMyte in a comment below. What I have now is this:

$(document).ready (function() {
    $('.xxxMenu > li').on('mouseover', openSubMenu);
    $('.xxxMenu > li').on('mouseout', closeSubMenu);

    function openSubMenu() {
        $(this).find('ul').css('visibility', 'visible').delay( 800 ).animate({opacity: 1.0}, 500);  
    };

    function closeSubMenu() {
        $(this).find('ul').css('visibility', 'hidden'); 
    };     
});

This shows the submenus after a short delay. The animation is quick, but the point of using animate is that it lets me set a delay. The only problem is that it seems to work only the first time it's triggered, on any given menu item. Once that submenu has been triggered, subsequent mouseovers go back to the old behavior, popping the submenu up instantly. I'll be looking into why and how to fix it but if anyone knows please let me know.

Thanks for all the suggestions, much appreciated.

2
  • Have you looked at animate() function in jquery API ? Commented Dec 15, 2014 at 21:47
  • Thanks for this, I had used animate elsewhere successfully so this was a good idea to try it here. See my update, and thanks again. Commented Dec 16, 2014 at 14:34

2 Answers 2

2

jsFiddle Demo

You would wrap the show and hide code with the setTimeoutMDN. Keep in mind that the function callback in setTimeout runs at the global level, so this will be window and you will need to store this into something like self as shown

function openSubMenu() {
 var self = this;
 setTimeout(function(){
  $(self).find('ul').css('visibility', 'visible');
 },350);
};

function closeSubMenu() {
 var self = this;
 setTimeout(function(){
  $(self).find('ul').css('visibility', 'hidden'); 
 },350);
};

$('.xxxMenu > li').on('mouseover', openSubMenu);
$('.xxxMenu > li').on('mouseout', closeSubMenu);

$('.xxxMenu > li').find('ul').css('visibility', 'hidden');

function openSubMenu() {
    var self = this;
    setTimeout(function(){
    $(self).find('ul').css('visibility', 'visible');
    },350);
};

function closeSubMenu() {
    var self = this;
    setTimeout(function(){
    $(self).find('ul').css('visibility', 'hidden'); 
    },350);
};
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul class="xxxMenu">
  <li><a href="#">Top Title</a>
    <ul>
      <li><a href="http://blahblah">Title One</a></li>
      <li><a href="http://blahblah">Title Two</a></li>
    </ul>
  </li>
</ul>


Alternatives

jsFiddle Demo

Another way to do this would be to use jQuery's built in fadeOutjQuery API, as well as stopjQuery API to prevent the fading from overqueueing.

function openSubMenu() {
 $('ul',this).stop().fadeIn('slow');
};

function closeSubMenu() {
 $('ul',this).stop().fadeOut('fast');
};

$('.xxxMenu > li').on('mouseover', openSubMenu);
$('.xxxMenu > li').on('mouseout', closeSubMenu);

$('.xxxMenu > li').find('ul').hide();

function openSubMenu() {
    $('ul',this).stop().fadeIn('slow');
};

function closeSubMenu() {
    $('ul',this).stop().fadeOut('fast');
};
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul class="xxxMenu">
  <li><a href="#">Top Title</a>
    <ul>
      <li><a href="http://blahblah">Title One</a></li>
      <li><a href="http://blahblah">Title Two</a></li>
    </ul>
  </li>
</ul>

Sign up to request clarification or add additional context in comments.

Comments

0

Are you set on using your own setTimeout to do it? If not, instead of setting the css visibility, use jquery's show/hide and then you can specify animation, delay, etc. See http://api.jquery.com/show/

http://jsfiddle.net/xa7qk4tc/1/

Note: mouseout has been changed to mouseleave

$('.xxxMenu > li').on('mouseover', openSubMenu);
$('.xxxMenu > li').on('mouseleave', closeSubMenu);

$('.xxxMenu > li').find('ul').hide();

function openSubMenu() {
    $(this).find('ul').show('slow');
};

function closeSubMenu() {
    $(this).find('ul').hide('slow');
};

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.