I've homerolled a Javascript based nav bar (I want it to be click, not hover for mobile friendliness). I've tried to make the HTML, CSS, and Javascript as simple as possible.
I put a listener on the body to close the menu bars if you click anywhere else on the website. I'm trying to filter the listener so that it does not fire if you click on any part of the menu bar. This is to prevent the dropdowns from rolling back up when you click on an element in the dropdown.
I expect the below matcher to ONLY match items that are descendants of the top level menu element. Any advice on why this isn't working would be much appreciated.
EDIT: I understand that you can use an arbitrary function to evaluate the bubble coming up and decide on whether or not you should act on it, but I'm more interested in why the below .on() selector is not working the way I expect.
$("body").on("click", ":not(#menu *)", function (e) {
$("#menu a").next().slideUp(DROP_DOWN_TIME);
});
HTML
<body>
<div>HEADER</div>
<ul id="menu" class="cf">
<li><a href="#">FooafsdasiuhfauhfuahsdfFooaf sdasiuhfauhfuahsdfFooafsdasiuhfauhfuahsdf</a>
<ul>
<li><a href="#">Subitem asdasdasd 1 sadad</a>
</li>
<li>Subitem 2</li>
<li>Subitem 3</li>
</ul>
</li>
<li><a href="#">Bar</a>
<ul>
<li>Subitem 1</li>
<li>Subitem 2</li>
<li>Subitem 3</li>
</ul>
</li>
<li>Qux</li>
</ul>
<div>CONTENT</div>
<div>FOOTER</div>
</body>
JAVASCRIPT
$(document).ready(function () {
var DROP_DOWN_TIME = 200;
//Setup hidden dropdowns
$("#menu > li > a").next().toggle();
//Hide or unhide dropdowns onclick
$("#menu > li > a").click(function (e) {
$("#menu a").next().not($(e.target).next()).slideUp(DROP_DOWN_TIME);
$(e.target).next().slideToggle(DROP_DOWN_TIME);
e.stopPropagation();
});
$("body").on("click", ":not(#menu *)", function (e) {
$("#menu a").next().slideUp(DROP_DOWN_TIME);
});
});
CSS
#menu {
width: 900px;
padding: 0;
margin: 0;
}
/* Top level menu container */
#menu li {
background-color: aqua;
border: 1px solid black;
padding: 2px;
}
/* Top level menu items */
#menu > li {
display: inline-block;
float: left;
position: relative;
}
/* Submenu container */
#menu > li > ul {
position:absolute;
padding: 0;
margin: 0;
top: 100%;
left: -1px;
}
/* Submenu Items */
#menu > li > ul > li {
display: block;
float: none;
white-space: nowrap;
}
.cf:before, .cf:after {
content:" ";
/* 1 */
display: table;
/* 2 */
}
.cf:after {
clear: both;
}
It is failing because the click is being caught on the menu element. The content inside is being caught.
You need to also add the menu element
$("body").on("click", ":not(#menu, #menu *)", function (e) {
^^^^^^