Help with Submenu (mouseover/mouseout)

Hi there,

I am very new to javascript so please go easy on me lol.

My task sounds quite simple: To create a submenu that appears when I mouseover a “top level” link and disappears if I move my mouse off of that link.

I have searched the internet and managed to find various sources of information on the use of mouseover and mouseout commands and have managed to piece together a code that does just that… however, there is 1 more part to the code that I cannot find.

It will be easier for me to show you the page that I’m designing…

www.cbresources.co.uk/ivegotkids

That is my test page.

You will see there is a line of buttons “home, community, shop etc…”

Whenever you hover over one of those buttons, a sub menu appears beneath them. If you hover off the button, the menu waits 2 seconds and then disappears.

Now my problem… I need to cancel the mouseout action if I am hovered over the sub menu… So basically, I want the sub menu to disappear after 2 seconds UNLESS I am on it… Otherwise, I cannot select any of the links in the submenu because it disappears.

Can somebody help me out here?

One of your options, based on what you have already done is to set a global boolean “submenuHover” to false when you mouse over a menu item. When you mouse over the submenu, the boolean is set to true, and back to false on mouse out.

The function that makes the submenu appear or disappear should first check the boolean before executing further

Hi there & thanks for your reply. However, as I pointed out in my original post I am new to javascript so I have no idea what a boolean is and trying to create one at this point would probably confuse my situation even more.

I have just been on my test site again and noticed that my original code isn’t working as I thought it was. It appears the 2 second delay that I put on the button’s mouse out command is activating even when I don’t mouse out so I’ve obviously done something wrong…

Maybe it would be best if somebody could just write an example code for me…

This is what I need it to do:

button 1: Mouseover = Submenu 1 appears, Mouseout = Submenu Disappears (after 2 seconds)

button 2: Mouseover = Submenu appears, Mouseout = Submenu Disappears (after 2 seconds)

Submenu 1: Mouseover = Menu stays active (cancels any previous Mouseout command), Mouseout = Menu disappears (after 2 seconds)

Submenu 2: Mouseover = Menu stays active (cancels any previous Mouseout command), Mouseout = Menu disappears (after 2 seconds)

That is the basics of it… I have 7 buttons in total, each bringing up 7 different sub menus. You can see an example of what I’m trying to achieve on the test site at the moment. Link is in my original post.

I think it looks like an event targeting/bubbling issue.

Basically what’s happening is that you’ve got a load of unwanted mouseover and mouseout events firing off left right and centre. You need to filter those events out.

This link here should be useful to you. Especially the ‘Mousing out of a layer’ section.

http://www.quirksmode.org/js/events_mouse.html

Oh yes, just remembered Mouseenter and mouseleave. Mentioned at the end. These are IE specific options, and ignore the bubbling. If you’re sniffing out browswers, you maybe able to use these instead.

Edit: just one last thing. Have you looked into the possibilty of doing this in CSS?

RLM

Hi,

I’ve just read through that page you linked to and it kind of makes sense but I’m still not clear on how to actually translate what they say into my actual code.

I can see that I need to add some kind of To and From element to my mouseout commands but it’s totally alien to me and I cannot really put it into practice without a working example - So if somebody could look at my code and tell me what it should be, that’d be great…

The code within my “head” tag…


<script type="text/javascript">
function showsubmenu(id){
submenu = document.getElementById('s'+id);
for(i=1;i<=7;i++){
if(i==id){
submenu.style.display="block";
} else {
document.getElementById('s'+i).style.display="none";
}
}
}
</script>
<script type="text/javascript">
function hidesubmenu(id){
submenu = document.getElementById('s'+id);
for(i=1;i<=7;i++){
if(i==id){
submenu.style.display="none";
} else {
document.getElementById('s'+i).style.display="none";
}
}
}
</script>

The code attached to each of my buttons


<a href="http://www.cbresources.co.uk/ivegotkids/index.php" onmouseover="javascript:showsubmenu(1)" onmouseout="setTimeout('hidesubmenu(1)();',2000);"><img src="http://www.cbresources.co.uk/ivegotkids/wp-content/themes/thepink/images/home.png" width="70px" height="32px"></a> <a href=2"http://www.cbresources.co.uk/ivegotkids/community/" onmouseover="javascript:showsubmenu(2)" onmouseout="setTimeout('hidesubmenu(2)();',2000);"><img src="http://www.cbresources.co.uk/ivegotkids/wp-content/themes/thepink/images/community.png" width="125px" height="32px"></a>

And finally… the code that I have for the submenu itself…


<div id="sublinks">
<ul id="s1">
Link 1, Link 2, Link 3
</ul>
</div>

<ul id="s2">
<div id="sublink2">
<li><a href="/forum/">Forums</a></li><li><a href="/chat/">Chat</a></li>
</div>
</ul>


There is quite a lot involved, and quite a bit of trial and error. The main chapter of learning is Events.

You’d also want to look into setting something up unobtrusively using methods like addEventListener and attachEvent in conjunction with handler methods. (I may have a go at an example later. A bit of a refresher:))

In the meantime… I mentioned you could look at a CSS menu instead. Something along the lines of the ‘Suckerfish’ menu. The advantages are

  1. If javascript is switched off you still have a functioning menu

and

  1. You’re cutting down on your amount of javascript, which should in theory optimise things.

The code would look a bit like this. Please note my CSS isn’t great.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<title>Navigation</title>
<style type="text/css">
ul.navbar, ul.navbar ul {
  position: relative;
  float: left;
  margin: 0; padding: 0px;
  list-style-type: none;
  background: none;
  text-align: center;
  font: normal 14px/24px arial, sans-serif;
}

ul.navbar li {
  padding-bottom: 5px; /* for space between menus but keeping hover */
  float: left;
}

ul.navbar li ul {
  position: absolute;
  width: 848px;
  top: 29px;
  left: -999em; /* hides menus of screen */
  border: none;
  background-color: orange;
}

.navbar li:hover ul {
  left: -1px; /*brings them back on on hover*/
}

ul.navbar li ul li {
  padding-bottom: 0px;
}

ul.navbar a {
  display: block;
  text-decoration: none;
  width: 120px; height: 24px;
  border: 1px solid black;
  border-right: none;
  background-color: #8bd400; /*could replace with an image*/
  color: #2b3f00;
}

ul.navbar li ul li a {
  background: none;
  border: none;
  width: auto;
  height: 28px; line-height: 28px;
  padding: 0 25px 0 25px;
}

ul.navbar li a.lastChild {
  border-right: 1px solid black;
}

</style>
</head>
<body>
<ul class="navbar">
  <li><a href = "/Home/">Home</a></li>
  <li><a href = "/Community/">Community</a>
    <ul>
	  <li><a href = "/Community/forums">Forums</a></li>
	  <li><a href = "/Community/chat">Chat</a></li>
    </ul>
  </li>
  <li><a href = "/Classifieds/">Classifieds</a>
    <ul>
	  <li><a href = "/Classifieds/browseAds">Browse Ads</a></li>
	  <li><a href = "/Classifieds/postAds">Post Ads</a></li>
    </ul>
  </li>
  <li><a href = "/Shop/">Shop</a>
    <ul>
	  <li><a href = "/Shop/browseAuctions">Browse Auctions</a></li>
	  <li><a href = "/Shop/sellItems">Sell an Item</a></li>
    </ul>
  </li>
  <li><a href = "/Astrology/">Astrology</a>
    <ul>
	  <li><a href = "/Astrology/horoscopes">Daily Horoscopes</a></li>
	  <li><a href = "/Astrology/reports">Personal Reports</a></li>
    </ul>
  </li>
  <li><a href = "/Charts&Tools/">Charts & Tools</a>
    <ul>
	  <li><a href = "/chartsTools/dueDateCalc">Due Date Calculator</a></li>
	  <li><a href = "/chartsTools/babyName">Baby Name Finder</a></li>
	  <li><a href = "/chartsTools/ovulation">Ovulation Predictor</a></li>
	  <li><a href = "/chartsTools/weightCharts">Weight Charts</a></li>
    </ul>
  </li>
  <li><a class="lastChild" href = "/Fun&Games/">Fun & Games</a>
    <ul>
	  <li><a href = "/funGames/games">Games</a></li>
	  <li><a href = "/funGames/links">Links</a></li>
    </ul> 
  </li>
</ul>     
</body>
</html>

Here’s a working example I’ve knocked up using images for buttons, with roll-overs. No javascript.

http://www.pixel-shack.com/critter/subMenu.html

RLM

I’ve put together a basic Javascript-based skeleton, that demonstrates all the different things you need to do to make it work:

<!DOCTYPE html>
<html>
<head>
<meta http-equiv=“Content-Type” content=“text/html; charset=utf-8”>
<title>Test Page</title>
<style>
ul {
list-style: outside none;
margin:0;
}

div#siteNav {
	margin:0;
	margin-left:0;
	width:100%;	
	height:auto;
	overflow:hidden;
	position:absolute;
	top:0;
	left:0;
	border:solid thin #000;
}

ul#mainmenu {
	position:relative;
	top:0;
	left:0;
	width:100%;
	height:40px;
	z-index:1000;
	overflow:hidden;
}

ul#mainmenu li.menuitem {
	float:left;
	padding:10px;
}

#submenu {
position:relative;
top:0;
left:0;
z-index:2;
width:100%;
height:40px;
overflow:hidden;
}

#submenu ul {
width:100%;
height:auto;
position:absolute;
top:0;
left:0;
overflow:hidden;
display:none;
}

#submenu ul.current {
display:block;
}

#submenu ul li {
float:left;
width:auto;
height:auto;
margin:10px;
overflow:hidden;
}

</style>
</head>
<body>

<div id=“siteNav”>
<ul id=“mainmenu”>
<li class=“menuitem”>
<a class=“menuitem” data-item=“1” href=“index.cfm?fuseaction=agent”>Become an Agent</a>
</li>
<li class=“menuitem”>
<a class=“menuitem” data-item=“2” href=“index.cfm?fuseaction=faq”>FAQ</a>
</li>
<li class=“menuitem”>
<a class=“menuitem” data-item=“3” href=“index.cfm?fuseaction=rap”>Earn Extra $</a>
</li>
<li class=“menuitem”>
<a class=“menuitem” data-item=“4” href=“index.cfm?fuseaction=educator”>Real Estate Educators</a>
</li>
<li class=“menuitem”>
<a class=“menuitem” data-item=“5” href=“index.cfm?fuseaction=jobdescription”>Agent Job Description</a>
</li>
</ul>
<div id=“submenu”>
<ul data-item=“1”>
<li>
<a class=“subitem” href=“index.cfm?fuseaction=agent”>Become an Agent - sub 1</a>
</li>
<li>
<a class=“subitem” href=“index.cfm?fuseaction=faq”>FAQ - sub 1</a>
</li>
<li>
<a class=“subitem” href=“index.cfm?fuseaction=rap”>Earn Extra $ - sub 1</a>
</li>
<li>
<a class=“subitem” href=“index.cfm?fuseaction=educator”>Real Estate Educators - sub 1</a>
</li>
<li>
<a class=“subitem” href=“index.cfm?fuseaction=jobdescription”>Agent Job Description - sub 1</a>
</li>
</ul>
<ul data-item=“2”>
<li>
<a class=“subitem” href=“index.cfm?fuseaction=agent”>Become an Agent - sub 2</a>
</li>
<li>
<a class=“subitem” href=“index.cfm?fuseaction=faq”>FAQ - sub 2</a>
</li>
<li>
<a class=“subitem” href=“index.cfm?fuseaction=rap”>Earn Extra $ - sub 2</a>
</li>
<li>
<a class=“subitem” href=“index.cfm?fuseaction=educator”>Real Estate Educators - sub 2</a>
</li>
<li>
<a class=“subitem” href=“index.cfm?fuseaction=jobdescription”>Agent Job Description - sub 2</a>
</li>
</ul>
<ul data-item=“3”>
<li>
<a class=“subitem” href=“index.cfm?fuseaction=agent”>Become an Agent - sub 3</a>
</li>
<li>
<a class=“subitem” href=“index.cfm?fuseaction=faq”>FAQ - sub 3</a>
</li>
<li>
<a class=“subitem” href=“index.cfm?fuseaction=rap”>Earn Extra $ - sub 3</a>
</li>
<li>
<a class=“subitem” href=“index.cfm?fuseaction=educator”>Real Estate Educators - sub 3</a>
</li>
<li>
<a class=“subitem” href=“index.cfm?fuseaction=jobdescription”>Agent Job Description - sub 3</a>
</li>
</ul>
<ul data-item=“4”>
<li>
<a class=“subitem” href=“index.cfm?fuseaction=agent”>Become an Agent - sub 4</a>
</li>
<li>
<a class=“subitem” href=“index.cfm?fuseaction=faq”>FAQ - sub 4</a>
</li>
<li>
<a class=“subitem” href=“index.cfm?fuseaction=rap”>Earn Extra $ - sub 4</a>
</li>
<li>
<a class=“subitem” href=“index.cfm?fuseaction=educator”>Real Estate Educators - sub 4</a>
</li>
<li>
<a class=“subitem” href=“index.cfm?fuseaction=jobdescription”>Agent Job Description - sub 4</a>
</li>
</ul>
<ul data-item=“5”>
<li>
<a class=“subitem” href=“index.cfm?fuseaction=agent”>Become an Agent - sub 5</a>
</li>
<li>
<a class=“subitem” href=“index.cfm?fuseaction=faq”>FAQ - sub 5</a>
</li>
<li>
<a class=“subitem” href=“index.cfm?fuseaction=rap”>Earn Extra $ - sub 5</a>
</li>
<li>
<a class=“subitem” href=“index.cfm?fuseaction=educator”>Real Estate Educators - sub 5</a>
</li>
<li>
<a class=“subitem” href=“index.cfm?fuseaction=jobdescription”>Agent Job Description - sub 5</a>
</li>
</ul>
</div>
</div>
<script>

var rootElem = document.getElementById('siteNav');
var currentSub = null;
var elems = document.getElementById('mainmenu').getElementsByTagName('a');
var i = 0; var iMax = elems.length;
while(i &lt; iMax) {
	if(elems[i].nodeName == 'A') {
		if(typeof document.addEventListener != 'undefined') {
		elems[i].addEventListener('mouseover', function(event) {
			var evt = event || window.event;
			var source = evt.srcElement || evt.target;
			var elemIndex = parseInt(source.getAttribute('data-item')) - 1;
			if(currentSub != null) { currentSub.className = ''; }
			currentSub = document.getElementById('submenu').getElementsByTagName('ul')[elemIndex];
			currentSub.className = 'current';
		}, false);
		}
		else {
		elems[i].attachEvent('onmouseover', function(event) {
			var evt = event || window.event;
			var source = evt.srcElement || evt.target;
			var elemIndex = parseInt(source.getAttribute('data-item')) - 1;
			if(currentSub != null) { currentSub.className = ''; }
			currentSub = document.getElementById('submenu').getElementsByTagName('ul')[elemIndex];
			currentSub.className = 'current';
		});
		}
	}
	i++;
}
	
if(typeof document.addEventListener != 'undefined') {
document.getElementById('siteNav').addEventListener('mouseout', function(event) {
	var evt = event || window.event;
	var source = evt.srcElement || evt.target;
	var from = evt.relatedTarget;
	if(source.parentNode === from.parentNode || from.nodeName == 'HTML') {
		currentSub.className = '';
		currentSub = null;
	}
}, false);
}
else {
document.getElementById('siteNav').attachEvent('onmouseout', function(event) {
	var evt = window.event;
	var source = evt.srcElement || evt.target;
	var from = evt.fromElement || evt.relatedTarget;
	if(source.parentNode === from.parentNode || from.nodeName == 'HTML') {
		currentSub.className = '';
		currentSub = null;
	}
});
}

</script>
</body>
</html>

I’ve put together a basic Javascript-based skeleton, that demonstrates all the different things you need to do to make it work:

Fair play to you:tup:

RLM

RLM, Thanks very much, I love your example. It is exactly what I want for the functionality of the menu.

I have two questions for you in relation to this CSS Menu…

  1. If you take a look at my test site now, you’ll see I’ve put it on there with my own buttons… the submenu works perfectly, but appears underneath what is already on the page. Can this be changed?

  2. Is there a way to change the background colour of the submenu for each button?

Your welcome:)

What’s probably best is if you take this over to the CSS forum now, where they can rip apart my flawed CSS and get you on the right track.:smiley:

RLM