Right now, I'm trying to build a vertical menu that will have a drop down sub menu below it.
Below is my HTML and the jQuery function I am using:
$(function() {
$('#menusomething > li').click(function(e) {
e.stopPropagation();
var $el = $('ul', this);
$('#menusomething > li > ul').not($el).slideUp();
$el.stop(true, true).slideToggle(400);
});
$('#menusomething > li > ul > li').click(function(e) {
e.stopImmediatePropagation();
});
});
<div id="navmenu">
<ul id="menusomething" style="padding-left:30px">
<li>HOME</li>
<li>ABOUT</li>
<li>CHAPTERS</li>
<ul class="submenu">
<li>Dallas</li>
<li>Los Angeles</li>
<li>New York</li>
<li>Northern California</li>
<li>Orange County</li>
<li>Phoenix</li>
<li>San Diego</li>
<li>Washington DC</li>
</ul>
<li>MEMBER SERVICES</li>
Figured out the answer for anyone who sees this. First had to move the closing li tag from chapters to the end of .submenu Then used this and now it works as wanted.
$(function() {
$('#menusomething li > .submenu').parent().click(function() {
var submenu = $(this).children('.submenu');
if ( $(submenu).is(':hidden') ) {
$(submenu).slideDown(400);
} else {
$(submenu).slideUp(400);
}
});
});
The following code does what I believe you desire: Have a <ul> element that is the nextElementSibling of the first level <li> element slide open and closed when it is clicked. As you mentioned in comments that you desired, it now starts closed due to adding style="display: none;" to the <ul>.
Note: From a user interface perspective, the <li> entries which don't have sub-menus, or are otherwise links, should not have the text enclosed in <a> tags. With the <a> tags the user will think they are clickable, when a click does nothing. This is confusing to a user. It appears that you may have some be sub-menus and some be direct links. If possible, there should be some visual difference between the two types to hint to the user as to what will happen when they click.
Along with other issues, your HTML has nothing that will match either the '#menusomething > li > ul' or the '#menusomething > li > ul > li' selectors. Specifically, you have no <UL> elements that are children of <LI> elements.
$(function() {
$('#menusomething > li').click(function(e) {
e.stopPropagation();
var nextSib = this.nextElementSibling;
if(nextSib && nextSib.nodeName === 'UL') {
//If we get here the nextSib exists and is a <UL> that immediately follows
// the <LI> which was clicked.
$(nextSib).slideToggle(400);
}
});
$('#menusomething > ul > li').click(function(e) {
console.log('Clicked on chapter: ' + this.textContent);
e.stopImmediatePropagation();
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<div id="navmenu">
<ul id="menusomething" style="padding-left:30px">
<li>HOME</li>
<li>ABOUT</li>
<li>CHAPTERS</li>
<ul class="submenu" style="display: none;">
<li>Dallas</li>
<li>Los Angeles</li>
<li>New York</li>
<li>Northern California</li>
<li>Orange County</li>
<li>Phoenix</li>
<li>San Diego</li>
<li>Washington DC</li>
</ul>
<li>MEMBER SERVICES</li>
</ul>
</div>
Related
Example: https://jsfiddle.net/lmgonzalves/xj6a74jy/1/
Result: I would like to make a slideUp + slideDown menu the has multiple levels.
I'm stuck trying to get this slide menu to work and I'm not sure how about to get it to work. I've tried using "height"0px" on some css when clicked but ultimately I get back to the same problem. I can make it through the first click in making the slide menu work (meaning there is a slideUp and slideDown), but any level after that the slider just slides up and not down leaving me with no visible menu. Here is what I have:
$('.mobile-nav .navigation a').on('click',function(e){
e.preventDefault();
var t = $(this);
var active = t.closest('li.active');
active.children('ul,a, li.back').not(t.closest('ul')).slideUp();
t.next('ul').slideDown();
});
.mobile-nav .navigation {background:#eee; width:250px; position:relative;}
.mobile-nav .navigation ul {margin:0; padding:0;}
.mobile-nav .navigation a {display:block; line-height:30px;}
.mobile-nav .navigation li ul {display:none;}
<div class="mobile-nav">
<div class="navigation">
<ul>
<li class="active">
All
<ul style="display:block;">
<li>
Topic 1
<ul>
<li class="back">Back</li>
<li>
Some Topic
<ul>
<li class="back">Back</li>
<li>
Some Topic1
((( the menu keeps getting repeated here going deeper, using the format of BackTopic 1Topic 1Topic2 with varying number of li's in each ul.
So the first ul looks like this:
<div class="mobile-nav">
<div class="navigation">
<ul>
<li class="active">
All
</li>
</ul>
/* With 3 more ul's and li's in each
<ul></ul>
<ul></ul>
<ul></ul>
</div>
</div>
When I click on one of the a href tag's, the menu slides to the next level showing the ul, which is the 2nd ul. But when I click on any of the li a's within this ul, I can see the menu start to slide down, but at the same time, the entire ul slides up showing nothing. The ul that was opened now is display:none; even though the next ul is now showing block. I can't figure out how to keep the slides going as they were in the first click.
I can redo classes and such if there is a better way to make this happen.
Fiddled something for you: Fiddle
Hope this is what you need. Just changed the way of selecting the elements.
(function ($) {
"use strict";
$('.mobile-nav')
.on('click', 'a', function (e) {
var $cTarget = $(e.currentTarget),
$dropdown = $cTarget.next('ul'),
$parentUl = $cTarget.closest('ul'),
$activeElem = $parentUl.find('ul.active');
$parentUl.children('li').each(function (key, elem) {
var $elem = $(elem);
if(!$cTarget.parent('li').is($elem)) {
$elem.slideUp();
}
});
$activeElem.toggleClass('active').slideUp();
if (!$dropdown.is($activeElem)) {
$dropdown.toggleClass('active').slideDown();
}
})
.on('click', '.back', function (e) {
var $cTarget = $(e.currentTarget),
$dropdown = $cTarget.closest('ul');
$dropdown.toggleClass('active').slideUp();
$cTarget.parents('li').first().siblings().slideDown();
});})(jQuery);
So these answers are going to be pretty close to each other, but I haven't seen one that meets your "only one item can be open at a time criteria." The JQuery is a little verbose if you want to stick with slipeUp and slideDown but here's an example of the code for handling it for the top-level unordered lists:
$('.toplevel > span').click(function () {
if ($(this).parent().hasClass('activeTop')) {
$('.activeTop').removeClass('activeTop');
$(this).parent().children('ul').slideUp();
return;
}
$('.activeTop').children('ul').slideUp();
$('.activeTop').removeClass('activeTop');
$(this).parent().addClass('activeTop');
$('.activeTop').children('ul').slideDown();
});
I replaced the a tags with spans (and cleaned up the HTML a bit) so I didn't have to deal with my demo fiddle navigating away, but here's a demo implementing the behavior for both top- and second-level menu items.
Check out this fiddle, I would make your structure a little simpler like this https://jsfiddle.net/jk90pxgt/1/ and then your jQuery is only a couple of lines. You can obviously add back buttons if you would like and styling is up to you but this is just a much cleaner way to do the slide menu. Also don't use links and prevent the default, it is just extra code. Just do your click function on the LI
Here is the jQuery
$(".mobile-menu li").click(function(e){
e.stopPropagation();
$(this).children(".sub-menu").slideToggle();
});
New HTML Structure
<ul class="mobile-menu">
<li>First Item
<ul class="sub-menu">
<li>First Sub-Item
<ul class="sub-menu">
<li>First Sub-Item</li>
<li>Second Sub-Item</li>
</ul>
</li>
<li>Second Sub-Item</li>
</ul>
</li>
<li>Second Item
<ul class="sub-menu">
<li>First Sub-Item
<ul class="sub-menu">
<li>First Sub-Item
<ul class="sub-menu">
<li>First Sub-Item</li>
<li>Second Sub-Item</li>
</ul>
</li>
<li>Second Sub-Item</li>
</ul>
</li>
<li>Second Sub-Item</li>
</ul>
</li>
<li>Third Item</li>
</ul>
And CSS
.sub-menu {
display:none;
}
li {
cursor:pointer;
}
Here is how I was able to make this work:
$('.mobile-nav .navigation a').on('click',function(e){
var t = $(this), li = t.closest('li'), ul = li.closest('ul'), a = ul.siblings('a');
if(li.hasClass('back')) {
e.preventDefault();
//do back code here
var sib = ul.closest('li').siblings('li');
a = ul.parents('ul').eq(0).siblings('a');
ul.slideUp();
sib.add(a).slideDown();
} else if(t.siblings().length > 0) {
e.preventDefault();
li.siblings('li').add(a).slideUp();
t.next('ul').slideDown();
}
});
I have a navigation from a ul, see below:
<nav>
<ul>
<li>Top Link 1</li>
<li>Top Link 2</li>
<ul>
<li><a href="#" >Sub Link 1</a></li>
<li>Sub Link 2</li>
<li>Sub Link 3</li>
</ul>
</li>
<li>Top Link 3</li>
<ul>
<li><a href="#" >Sub Link 1</a></li>
<li>Sub Link 2</li>
<li>Sub Link 3</li>
</ul>
</li>
</ul>
</nav>
I have my css, hiding the the sub link's "ul" unless hovering the parent "li". (Will not show unless asked, as this is not the issues)
I'm trying to use my JQuery to add a css style (margin-bottom:30px;) to the top level "li" only if it has a child "ul" nested in it. My JQuery is as below:
<script>
$(document).ajaxSuccess(function () {
if ($("nav ul >li").children("ul li")) {
$("nav ul >li").hover(function () {
$("nav ul >li").css("margin-bottom", "30");
});
}
});
</script>
This does not appear to be working for me, can anyone point out what I'm doing wrong? Or can they provide a better solution to this approach?
.children will always return an array, check .length
$(document).ajaxSuccess(function () {
if ($("nav ul >li").children("ul li").length > 0) {
$("nav ul >li").hover(function () {
$("nav ul >li").css("margin-bottom", "30");
});
}
});
Try a little something like this :
$('li > ul').each(function(){
$(this).parent().addClass("your class");
});
This will select all uls that are children of li's and apply the class to the respectful li.
you do have an extra </li> in your question which i think is a typo..
<li>Top Link 2</li>
//-------^^^^^here
<ul>
<li><a href="#" >Sub Link 1</a></li>
anyways you check check for length of children if present..
try this
$(document).ajaxSuccess(function () {
if ($("nav ul >li").children().length > 0) {
$("nav ul >li").hover(function () {
$(this).css("margin-bottom", "30");
});
}
});
.children() method returns an object and an object is a truthy value in JavaScript, apart from that if the condition is valuated to true, you are adding a listener to all the li elements not just those that have ul children, You can use .has() method which is a filtering method:
$("nav > ul > li").has('ul').on({
mouseenter: function() {
$(this).css("margin-bottom", "30px");
},
mouseleave: function() {
$(this).css("margin-bottom", "n");
}
});
Or:
li.hovered {
margin-bottom: 30px;
}
$("nav > ul > li").has('ul').on('mouseenter mouseleave', function(e){
$(this).toggleClass('hovered', e.type === 'mouseenter');
});
I got the following structure: - nested UL
<ul class="depth-one">
<li>Category 1
<ul class="depth-two">
<li > Category 1.1</li>
<li> Category 1.2</li>
<li> Category 1.3</li>
</ul>
</li>
<li> Category 2
<ul class="depth-two">
<li>Category 2.1</li>
<li>Category 2.2</li>
<li>Category 2.3</li>
</ul>
</li>
<li>Category 3
<ul class="depth-two">
<li>Category 3.1</li>
<li>Category 3.2</li>
<li>Category 3.3</li>
</ul>
</li>
</ul>
I've applied a rule with CSS:
ul{
list-style: none;
padding:0;
margin:0;
}
.depth-one{
display:block;
}
.depth-two{
display:none;
}
which leaves only the MAIN category shown.
$(document).ready(function() {
$(".depth-one > li").click(function() {
selector = $(this).find(' > .depth-two');
if($(selector).css("display") == "none"){
selector.slideDown(800);
} else {
selector.slideUp(800);
}
});
});
this one, toggles the SUB categories when the MAIN category is being clicked.
here is a fiddle to demonstrate: http://jsfiddle.net/NB4bN/1/
Now, as you can see, when I'm clicking on the SUBCATEGORY, the whole category slides up, any idea why?
I'm trying to achieve that only when I click on the MAIN category, the subcategory will slides up, otherwise, nothing happens when I click on the sub <li> items.
Here is a fix for your problem: http://jsfiddle.net/smerny/NB4bN/2/
$(document).ready(function () {
$(".depth-one > li").click(function (e) {
if (e.currentTarget == e.target) {
selector = $(this).find(' > .depth-two');
if ($(selector).css("display") == "none") {
selector.slideDown(800);
} else {
selector.slideUp(800);
}
}
});
});
I added the check to see if currentTarget and target were the same. So you know if the click is on an element within your li or the li itself.
An easy fix is to stop the event bubbling by adding:
$('li li').click(function (e) {
e.stopPropagation();
});
jsFiddle example
.stoppropagation() prevents an event from bubbling up the DOM tree. So what the above chunk does is look for any list items that are children of other list items and whenever it registers a click on one, it stops the click event from bubbling up the DOM.
I have an accordion menu that the active link drops down the menu, loads an external page into a div, then changes the banner on the same click. I have everything working except for the banner image changing out. I thought I had the code right, but something seems to be missing, and I can't figure it out.
Here is my html:
<section id="commercialBanner">
<img src="images/catalog/indoorBanner.jpg"/>
</section>
<section id="accordionNav">
<ul id="nav">
<li id="indoorEntrance" class="category"><a class="ext" id="indoor" href="montage.html">Indoor Entrance</a>
<ul id="indoorEntranceSubmenu" class="sideSub">
<li>Ecomat Squares</li>
<li>Gatekeeper</li>
<li>Absorba</li>
</ul>
</li>
<li id="outdoorEntrance" class="category"><a id="outdoor" class="ext" href="aquaFlow.html">Outdoor Mats</a>
<ul id="outdoorEntranceSubmenu" class="sideSub">
<li>AquaFlow</li>
</ul>
</li>
</ul>
<section id="catalog"></section>
Here is my Script:
$('a.ext').click(function (event){
event.preventDefault();
$('#catalog').load(this.href);
});
$('.category > a').click(function(evt) {
if ($(this).attr('class') != 'active'){
$('#nav li ul').hide();
$(this).next().show()
// $(this).next('li > a').trigger('click')
$('#nav li a').removeClass('active');
$(this).addClass('active');
};
if ($('#indoor').attr('class') == 'active'){
$("#commercialBanner img").attr("src", "images/catalog/indoorBanner.jpg");
};
if ($('#outdoor').attr('class') == 'active'){
$("#commercialBanner img").attr("src", "images/catalog/outdoorBanner.jpg");
};
});
You seem to be checking the class attribute incorrectly - you have more than one class on an element, so:
$('#indoor').attr('class') is 'ext active' or 'ext'
As noted by #epascarello: use hasClass("active").
See this:
jQuery's attr - return multiple classes not just the 1st
i'm having some trouble.
I'm doing an asp.net mvc3 application and i downloaded some css menu, the thing is i want to keep the menu active after menu tab its clicked and only change when another one is clicked.
here's the code of the menu on _Layout.cshtml
<nav>
<div class="cssmenu">
<ul>
<li class='active'><span>#Html.ActionLink("Início", "Index", "Home")</span></li>
<li><span>#Html.ActionLink("Tarefas Contabilidade", "SelectEmpresa", "Empresa")</span></li>
<li><a href='#'><span>Clientes</span></a>
<ul>
<li><span>#Html.ActionLink("Listar clientes", "ListarEmpresas", "Empresa")</span></li>
</ul>
</li>
<li><a href='#'><span>Balancetes</span></a>
<ul>
<li><span>#Html.ActionLink("Listar registos", "ListaBalancetesPorSalaoMes", "Balancete")</span></li>
</ul>
</li>
<li><span>#Html.ActionLink("Sobre", "About", "Home")</span></li>
</ul>
</div>
</nav>
and i have this script:
<script type="text/javascript">
$("li").click(function () {
$("li").removeClass("active");
$(this).addClass("active");
});
</script>
the first tab that i put there class= "active" works, but the script doesn't seem to work when i click another menu tab, it only shows the first one active
a little help please :)
UPDATED
This is the rendered html:
<nav>
<div class="cssmenu">
<ul>
<li><span>Início</span></li>
<li><span>Tarefas Contabilidade</span></li>
<li><a href='#'><span>Clientes</span></a>
<ul>
<li><span>Listar clientes</span></li>
<li><span>Listar salões</span></li>
<li><span>Gerir empregados</span></li>
<li><span>Novo cliente</span></li>
<li><span>Novo salão</span></li>
</ul>
</li>
<li><a href='#'><span>Balancetes</span></a>
<ul>
<li><span>Listar registos</span></li>
<li><span>Upload novo balancete</span></li>
<li><span>Mapa Resultados/Gráfico</span></li>
<li><span>Mapas Contabilidade/Gestão</span></li>
<li><span>Análise Rentabilidade</span></li>
<li><span>Alterar taxas</span></li>
</ul>
</li>
<li><span>Sobre</span></li>
</ul>
</div>
</nav>
i dont know if i should put the javascript inside the div or something xD
Ty
You can use child selector which selects all direct child elements, Try the following:
$(document).ready(function(){
$(".cssmenu > ul > li").click(function () {
$(this).siblings().removeClass("active");
$(this).addClass("active");
});
})
If you want to select the li tags of the inner ul tags, you can try:
$(document).ready(function() {
$("ul:eq(1) > li").click(function() {
$('ul:eq(1) > li').removeClass("active");
$(this).addClass("active");
});
})
Can you try:
<script type="text/javascript">
$("li a").bind('click', function () {
$("li").removeClass("active");
$(this).addClass("active");
});
</script>
li items are not clickable, so you must bind the click event to a.
try
$("li").click(function (e) {
e.preventDefault();
$(this).siblings().removeClass("active").end().addClass("active");
});