/    Sign up×
Community /Pin to ProfileBookmark

Drop Down Menu – delay timing + hiding functions

Hi everyone,

I’m new to this forum, and somewhat new to Javascript, so I’d greatly appreciate any help you can provide with my problem.

I’m working on a drop down menu for a website, and it is supposed to be a vertical dropdown menu where the submenu items appear below the menu item and thereby moving the menu items further down the page. Also there should be a timing element implemented to delay the disappearing of submenu items onmouseout (about a second or two).

I’ve implemented a timing element within the JS using setTimeOut which is working fine. However the issue I’ve come across is when you move the mouse from one menu or submenu item to the next menu item, the next menu will trigger showing the submenu items but the previous submenu items will not disappear. However “logically” one would think that it’s because if the submenu items would disappear it would rearrange the location of where the current menu and submenu items would be (moving them up). However I also noticed that if you move off the 2nd triggered menu item the first menu item and submenu items would not disappear. Someone suggested using jquery and using the line $(‘ul.cssdropdown’).css(‘display’, ‘none’); to select and hide all the other ul’s before showing the new ones. I’ve tried it out and it’s not working. Here is the code before using jQuery. It’s easier to see what kind of problem I’m talking about by running this code and playing with the mouseover/out triggers yourselves.

<html>
<head>
<style type=”text/css”>
#cssdropdown li.headlink ul { display: none; }
</style>
<script language=”JavaScript”>
window.onload = function()
{
var lis = document.getElementsByTagName(‘li’);
for(i = 0; i < lis.length; i++)
{
var li = lis[i];
if (li.className == ‘headlink’)
{
var showing = 0;
li.onmouseover = function() { self = this; showing = i; setTimeout(function(){ if (showing == i) self.getElementsByTagName(‘ul’).item(0).style.display = ‘block’; }, 500); }
li.onmouseout = function() { self = this; showing = 0; setTimeout(function(){ if (showing == 0) self.getElementsByTagName(‘ul’).item(0).style.display = ‘none’; }, 1000); }
}
}
}
</script>

</head>

<body>
<ul id=”cssdropdown”>
<li class=”headlink”><a href=”menu.html” class=”headerCssClass”>MENU</a>
<ul>
<li><a href=”submenu1.html” class=”itemCssClass”>SUBMENU1</a></li>
<li><a href=”submenu2.html” class=”itemCssClass”>SUBMENU2</a></li>
<li><a href=”submenu3.html” class=”itemCssClass”>SUBMENU3</a></li>
</ul>
</li>
</ul>
<ul id=”cssdropdown”>
<li class=”headlink”><a href=”menu.html” class=”headerCssClass”>MENU</a>
<ul>
<li><a href=”submenu1.html” class=”itemCssClass”>SUBMENU1</a></li>
<li><a href=”submenu2.html” class=”itemCssClass”>SUBMENU2</a></li>
<li><a href=”submenu3.html” class=”itemCssClass”>SUBMENU3</a></li>
</ul>
</li>
</ul>
<ul id=”cssdropdown”>
<li class=”headlink”><a href=”menu.html” class=”headerCssClass”>MENU</a>
<ul>
<li><a href=”submenu1.html” class=”itemCssClass”>SUBMENU1</a></li>
<li><a href=”submenu2.html” class=”itemCssClass”>SUBMENU2</a></li>
<li><a href=”submenu3.html” class=”itemCssClass”>SUBMENU3</a></li>
</ul>
</li>
</ul>
</body>
</html>

to post a comment
JavaScript

15 Comments(s)

Copy linkTweet thisAlerts:
@MrNobodyNov 20.2008 — I did this and got better behavior:
[code=html]<script type="text/javascript">
var currentMenu = null;
window.onload = function()
{
var lis = document.getElementsByTagName('li');
for(i = 0; i < lis.length; i++)
{
var li = lis[i];
if (li.className == 'headlink')
{
li.onmouseover = function()
{
if (currentMenu) currentMenu.getElementsByTagName('ul').item(0).style.display = 'none';
var that = currentMenu = this;
setTimeout(function() { if (currentMenu==that) that.getElementsByTagName('ul').item(0).style.display = 'block'; }, 500);
}
li.onmouseout = function()
{
var that = currentMenu = this;
setTimeout(function() { if (currentMenu==that) that.getElementsByTagName('ul').item(0).style.display = 'none'; currentMenu = null; }, 1000);
}
}
}
}
</script>[/code]
Copy linkTweet thisAlerts:
@phamauthorNov 20.2008 — really? I tried using your code and I was getting very strange behaviour. What I saw was that when I moused over it would pop up for about half a second and then disappear without me moving the mouse at all. Even when I tried to mouse onto the newly triggered items, they would disappear before I could reach them.

does this not happen with you?

note: I basically copied and pasted your script over the corresponding section on my html script.

Any suggestions?
Copy linkTweet thisAlerts:
@MrNobodyNov 20.2008 — Yes, there is an issue of mousing off of the menu selection to the submenu selection which has to be dealt with using a timer cancellation mechanism. But when mousing just from the bottom menu selection immediately to the one above, you should see much better behavior. Also, there is one correction to what I posted:
[CODE] li.onmouseout = function()
{
var that = currentMenu = this;
setTimeout(function() { if (currentMenu==that) { that.getElementsByTagName('ul').item(0).style.display = 'none'; currentMenu = null; } }, 1000);
}[/CODE]
Copy linkTweet thisAlerts:
@phamauthorNov 20.2008 — from the code you suggested, I'm still not seeing a fix in the problem. When I mouse on to the "menu" item, the submenu will pop up but disappear before I move my mouse. I can't see what you're saying about moving from the last item to the one above as there isn't anything above since it just flashes and disappears as mentioned.

the entire code I'm using right now (with your modifications) is as follows:
[CODE]
<html>
<head>
<style type="text/css">
#cssdropdown li.headlink ul { display: none; }
</style>
<script type="text/javascript">
var currentMenu = null;
window.onload = function()
{
var lis = document.getElementsByTagName('li');
for(i = 0; i < lis.length; i++)
{
var li = lis[i];
if (li.className == 'headlink')
{
li.onmouseover = function()
{
if (currentMenu) currentMenu.getElementsByTagName('ul').item(0).style.display = 'none';
var that = currentMenu = this;
setTimeout(function() { if (currentMenu==that) that.getElementsByTagName('ul').item(0).style.display = 'block'; }, 500);
}
li.onmouseout = function()
{
var that = currentMenu = this;
setTimeout(function() { if (currentMenu==that) { that.getElementsByTagName('ul').item(0).style.display = 'none'; currentMenu = null; } }, 1000);
}
}
}
}
</script>

</head>

<body>
<ul id="cssdropdown">
<li class="headlink"><a href="menu.html" class="headerCssClass">MENU</a>
<ul>
<li><a href="submenu1.html" class="itemCssClass">SUBMENU1</a></li>
<li><a href="submenu2.html" class="itemCssClass">SUBMENU2</a></li>
<li><a href="submenu3.html" class="itemCssClass">SUBMENU3</a></li>
</ul>
</li>
</ul>
<ul id="cssdropdown">
<li class="headlink"><a href="menu.html" class="headerCssClass">MENU</a>
<ul>
<li><a href="submenu1.html" class="itemCssClass">SUBMENU1</a></li>
<li><a href="submenu2.html" class="itemCssClass">SUBMENU2</a></li>
<li><a href="submenu3.html" class="itemCssClass">SUBMENU3</a></li>
</ul>
</li>
</ul>
<ul id="cssdropdown">
<li class="headlink"><a href="menu.html" class="headerCssClass">MENU</a>
<ul>
<li><a href="submenu1.html" class="itemCssClass">SUBMENU1</a></li>
<li><a href="submenu2.html" class="itemCssClass">SUBMENU2</a></li>
<li><a href="submenu3.html" class="itemCssClass">SUBMENU3</a></li>
</ul>
</li>
</ul>
</body>
</html>
[/CODE]
Copy linkTweet thisAlerts:
@MrNobodyNov 20.2008 — This is the problem you described:
However the issue I've come across is when you move the mouse from one menu or submenu item to the next menu item, the next menu will trigger showing the submenu items but the previous submenu items will not disappear.[/QUOTE]
I copied your code and tested it. The problem I noticed was when moving from the last MENU item to the MENU item above it. The submenu items for the last MENU item would not disappear when the submenu items for the second to last MENU item appeared. So, that is the issue I addressed. There is still an issue when going downward because the appearing and disappearing of submenu items plays havoc with the mouse position when you get several elements moving in and out of range without moving the mouse at all. But, as I said, applying a timer cancellation mechanism between menu item and submenu items is the fix for that. You know how to cancel timers?

timer = setTimeout(...);

clearTimeout(timer);
Copy linkTweet thisAlerts:
@phamauthorNov 20.2008 — I see... thanks for that clear up.

No I don't really know how to put up a cancellation mechanism. Where would I apply those codes you listed at the bottom of your last post? Could you just copy/paste the JS section to make it clear?
Copy linkTweet thisAlerts:
@MrNobodyNov 20.2008 — Basically, the mouseout setTimeout you've already got needs to start saving a pointer to its timer. That is the first line I posted. Then, you'd need a mouseover event for the submenu items. In that event is where you place the second line of code I posted in order to prevent the mouseout of the main menu entry from closing the submenu item entries.
Copy linkTweet thisAlerts:
@phamauthorNov 20.2008 — Basically, the mouseout setTimeout you've already got needs to start saving a pointer to its timer. That is the first line I posted. Then, you'd need a mouseover event for the submenu items. In that event is where you place the second line of code I posted in order to prevent the mouseout of the main menu entry from closing the submenu item entries.[/QUOTE]

I see what you mean... but I'm not quite understanding where to put them. I'm guessing the timer = setTimeout function has to be within the setTimeout function of both onmouseover and onmouseout am I right? Could you show me what you mean with the sample code I've posted previously? Please and thanks.
Copy linkTweet thisAlerts:
@MrNobodyNov 20.2008 — No, the mouseover event timer you have doesn't need to be saved -- just the mouseout event timer. Then you need a new event for the submenu items in which you'll place the timer cancellation.
Copy linkTweet thisAlerts:
@phamauthorNov 20.2008 — No, the mouseover event timer you have doesn't need to be saved -- just the mouseout event timer. Then you need a new event for the submenu items in which you'll place the timer cancellation.[/QUOTE]

so how would i go about implementing a new event for the submenu items? any suggestions. Sorry if I really sound amateurish/childish here. Really haven't got a clue.
Copy linkTweet thisAlerts:
@MrNobodyNov 20.2008 — So I take you didn't write the code you've got?
Copy linkTweet thisAlerts:
@phamauthorNov 20.2008 — admittedly, nail on the head sir :o

I based it off of an online tutorial which wasn't very descriptive.
Copy linkTweet thisAlerts:
@MrNobodyNov 21.2008 — OK, here it is:
[code=html]<script type="text/javascript">
var currentMenu = null;
var timer = null;
window.onload = function()
{
var lis = document.getElementsByTagName('li');
for(i = 0; i < lis.length; i++)
{
var li = lis[i];
if (li.className == 'headlink')
{
li.onmouseover = function()
{
if (currentMenu)
{
if (timer) window.clearTimeout(timer);
currentMenu.getElementsByTagName('ul').item(0).style.display = 'none';
}
var that = currentMenu = this;
window.setTimeout(function()
{
if (currentMenu==that) that.getElementsByTagName('ul').item(0).style.display = 'block';
}, 500);
return true;
}
li.onmouseout = function()
{
var that = currentMenu = this;
timer = window.setTimeout(function()
{
if (currentMenu==that)
{
that.getElementsByTagName('ul').item(0).style.display = 'none';
currentMenu = null;
}
}, 1000);
return true;
}
var lu = li.getElementsByTagName('ul').item(0);
lu.onmouseover = function(e)
{
if (timer) window.clearTimeout(timer);
if (e) e.cancelBubble = true;
else event.cancelBubble = true;
return true;
}
}
}
}
</script>[/code]
Copy linkTweet thisAlerts:
@phamauthorNov 21.2008 — thanks for the code there...

I tried it out but I'm seeing an issue when mousing off the first/second set of submenu items. The submenu items should be delayed as you mouse onto the next set of menu+submenu items and then disappear afterwards. The only case where this works as expected is with the last menu+submenu set.

the script is as follows:

[CODE]
<html>
<head>
<style type="text/css">
#cssdropdown li.headlink ul { display: none; }
</style>
<script type="text/javascript">
var currentMenu = null;
var timer = null;
window.onload = function()
{
var lis = document.getElementsByTagName('li');
for(i = 0; i < lis.length; i++)
{
var li = lis[i];
if (li.className == 'headlink')
{
li.onmouseover = function()
{
if (currentMenu)
{
if (timer) window.clearTimeout(timer);
currentMenu.getElementsByTagName('ul').item(0).style.display = 'none';
}
var that = currentMenu = this;
window.setTimeout(function()
{
if (currentMenu==that) that.getElementsByTagName('ul').item(0).style.display = 'block';
}, 1000);
return true;
}
li.onmouseout = function()
{
var that = currentMenu = this;
timer = window.setTimeout(function()
{
if (currentMenu==that)
{
that.getElementsByTagName('ul').item(0).style.display = 'none';
currentMenu = null;
}
}, 3000);
return true;
}
var lu = li.getElementsByTagName('ul').item(0);
lu.onmouseover = function(e)
{
if (timer) window.clearTimeout(timer);
if (e) e.cancelBubble = true;
else event.cancelBubble = true;
return true;
}
}
}
}
</script>

</head>

<body>
<ul id="cssdropdown">
<li class="headlink"><a href="menu.html" class="headerCssClass">MENU</a>
<ul>
<li><a href="submenu1.html" class="itemCssClass">SUBMENU1</a></li>
<li><a href="submenu2.html" class="itemCssClass">SUBMENU2</a></li>
<li><a href="submenu3.html" class="itemCssClass">SUBMENU3</a></li>
</ul>
</li>
<li class="headlink"><a href="menu.html" class="headerCssClass">MENU</a>
<ul></lu>
<li><a href="submenu1.html" class="itemCssClass">SUBMENU1</a></li>
<li><a href="submenu2.html" class="itemCssClass">SUBMENU2</a></li>
<li><a href="submenu3.html" class="itemCssClass">SUBMENU3</a></li>
</ul>
</li>
<li class="headlink"><a href="menu.html" class="headerCssClass">MENU</a>
<ul>
<li><a href="submenu1.html" class="itemCssClass">SUBMENU1</a></li>
<li><a href="submenu2.html" class="itemCssClass">SUBMENU2</a></li>
<li><a href="submenu3.html" class="itemCssClass">SUBMENU3</a></li>
</ul>
</li>
</ul>
</body>
</html>
[/CODE]


May it's just me, I don't really notice much of a difference between this and the original code.
Copy linkTweet thisAlerts:
@MrNobodyNov 21.2008 — Well, then I guess you can go back to the original code and find someone else to help you. You paid me nothing for my time, so all you've lost is the six hours that you've waited for me to clear some time in my busy days to do this free job for you -- which, by the way, I tested in both IE7 and FF3 with MUCH improved behavior over the original code. Cheers, my friend.
×

Success!

Help @pham spread the word by sharing this article on Twitter...

Tweet This
Sign in
Forgot password?
Sign in with TwitchSign in with GithubCreate Account
about: ({
version: 0.1.9 BETA 5.18,
whats_new: community page,
up_next: more Davinci•003 tasks,
coming_soon: events calendar,
social: @webDeveloperHQ
});

legal: ({
terms: of use,
privacy: policy
});
changelog: (
version: 0.1.9,
notes: added community page

version: 0.1.8,
notes: added Davinci•003

version: 0.1.7,
notes: upvote answers to bounties

version: 0.1.6,
notes: article editor refresh
)...
recent_tips: (
tipper: @AriseFacilitySolutions09,
tipped: article
amount: 1000 SATS,

tipper: @Yussuf4331,
tipped: article
amount: 1000 SATS,

tipper: @darkwebsites540,
tipped: article
amount: 10 SATS,
)...