Menu with slidable submenu container - javascript

I have menu defined with UL, LI... up to max one submenu:
ul
li: item 1
li: item 2
ul
li: item 2.1
li: item 2.2
li: item 3
ul
li: item 3.1
li: item 3.2
li: item 3.3
What I would like to achieve is to show submenu in a way that "sub menu item container" will slide to the next submenu when clicked. In example above this would mean:
when user clicks item 2, container with sub items will show
when user clicks item 3, container with somehow slide/animate/transition from item 2 to item 3, changing sub items
This transition should only happen if sub menu container is already visible... if not, it just shows up next to clicked menu item.
I am not sure how to approach this problem and would like your help on it.
Thank you!
EDIT:
This is hover enabled sample, no JS (I know onclick is not supported in CSS, but I can handle this later):
http://codepen.io/anon/pen/HDinB
This shows a bottom aligned main menu items. Each main menu item can have sub items (this is only one level deep menu, there will be no more sublevels). Submenu will contain no more than max 9 items which will fit into a box (black box you see). What I want is that subitems apear "in" that box, but when new main item with submenu items is selected this box will slide (if already visible) to the new position and kind of be wrapper for new subitems. Will this be a floating box, or real container, or something 3rd, I don't know because I don't realy know what would be best way to handle this.

I'm absolute no jQuery expert, and I presume that jQuery is okay for you.
I created you this function. When a submenu is expanded, the class expand is assigned to it.
When a link is clicked, the function will check if it has the expand class, if so, it will close the submenu. If not, all the other expand classes will be closed (if exist) and the submenu will be shown.
HTML:
<ul>
<li>item 1</li>
<li>item 2
<ul>
<li>item 2.1</li>
<li>item 2.2</li>
</ul>
</li>
<li>item 3
<ul>
<li>item 3.1</li>
<li>item 3.2</li>
<li>item 3.3</li>
</ul>
</li>
</ul>
CSS:
li ul {
display: none;
}
jQuery:
$(document).ready(function() {
$("li:has(ul) a").on('click', function(e) {
e.preventDefault();
var ul = $(this).parent().find('ul');
if( ul.hasClass('expand') ) {
ul.removeClass('expand').slideToggle()
}
else {
$('.expand').removeClass('expand').slideToggle();
ul.addClass('expand').slideToggle();
}
});
});
jsFiddle DEMO.
Hope it suits you, or at least helps you on your way.

<ul class="menu">
<li>item 1</li>
<li>item 2
<ul class="sub-menu">
<li>item 2.1</li>
<li>item 2.2</li>
</ul>
</li>
<li>item 3
<ul class="sub-menu">
<li>item 3.1</li>
<li>item 3.2</li>
<li>item 3.3</li>
</ul>
</li>
</ul>
<style type="text/css">
ul li{display:inline-block; position:relative;}
ul li ul{display:none;width:100%; position:absolute; white-space: nowrap;margin:0px;padding:0px;top:20px;}
ul li ul li{ display:block;}
</style>
<script type="text/javascript">
$(document).ready(function(){
$(".menu li").click(function(){
$(".menu li ul").slideUp();
if($(this).find("ul").css("display")=='block')
{
$(this).find("ul").slideUp();
}
else
{
$(this).find("ul").slideDown();
}
});
});
</script>

Related

jquery submenu: li items still toggling

I've been trying to figure it out for a few hours now and as i'm pretty new to jQuery itself and i'm definetely still a beginner i really need some help with this. I try to create a navigation with a submenu in it. Everything is working as intended but i am missing the way i can stop the list items of the submenu from toggling.
HTML:
<nav>
<ul id="site-nav">
<li>Main Nav Item 1</li>
<li>Main Nav Item 2 (with submenu)
<ul>
<li>Submenu Item 1</li>
<li>Submenu Item 2</li>
<li>Submenu Item 3</li>
</ul>
</li>
<li>Main Nav Item 3 (with submenu)
<ul>
<li>Submenu Item 1</li>
<li>Submenu Item 2</li>
</ul>
</li>
<li>Main Nav Item 4</li>
<li>Main Nav Item 5</li>
</ul>
</nav>
JQuery (submenu part):
$(document).ready(function() {
var subnavArrow = ['<div id="subnavArrow"></div>'];
subpull = $('header nav ul li');
submenu = $('header nav ul li ul');
submenuitems = $('header nav ul li ul li');
subpull.has('ul').prepend(subnavArrow);
$('header nav ul li').has('ul').click(function() {
$(this).children('ul').toggle('slow');
});
});
If you didn't catch what i mean, i try to explain it as thoroughly as i can:
I want to open the Main Nav Item 2's subitems per click on it (Main Nav Item 2). This is working as intented and i can also close it again, but if i click on a Submenu Item of "Main Nav Item 2" it will close down the Main Nav Item 2's submenu.
You can check whether you have clicked on the anchor or div element like
$(document).ready(function() {
var subnavArrow = ['<div id="subnavArrow"></div>'];
subpull = $('header nav ul li');
submenu = $('header nav ul li ul');
submenuitems = $('header nav ul li ul li');
subpull.has('ul').prepend(subnavArrow);
$('header nav ul li').has('ul').click(function(e) {
if ($(e.target).closest('li').is(this)) {
$(this).children('ul').toggle('slow');
}
});
});
#subnavArrow:after {
content: '<<'
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<header>
<nav>
<ul id="site-nav">
<li>Main Nav Item 1
</li>
<li>Main Nav Item 2 (with submenu)
<ul>
<li>Submenu Item 1
</li>
<li>Submenu Item 2
</li>
<li>Submenu Item 3
</li>
</ul>
</li>
<li>Main Nav Item 3 (with submenu)
<ul>
<li>Submenu Item 1
</li>
<li>Submenu Item 2
</li>
</ul>
</li>
<li>Main Nav Item 4
</li>
<li>Main Nav Item 5
</li>
</ul>
</nav>
</header>
Don't append #ID elements. ID should be unique. Use classes instead .subnavArrow
Refer in jQuery to #site-nav as the parent
Use Event.stopPropagation() (if you'll use more nested li>ul)
Always assign your var to variables, or concatenate using ,
$(function() { // DOM ready
var $LIsub = $("#site-nav li:has(ul)");
$LIsub.children("a").append('<span class="subnavArrow"/>');
$LIsub.click(function(e) {
e.stopPropagation();
$(this).find('> ul').slideToggle('slow');
});
});
#site-nav li ul{
display:none;
}
.subnavArrow:after{
content:"\25BC"
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<header>
<nav>
<ul id="site-nav">
<li>Main Nav Item 1</li>
<li>Main Nav Item 2
<ul>
<li>Submenu Item 1</li>
<li>Submenu Item 2</li>
<li>Submenu Item 3</li>
</ul>
</li>
<li>Main Nav Item 3
<ul>
<li>Submenu Item 1</li>
<li>Submenu Item 2</li>
</ul>
</li>
<li>Main Nav Item 4</li>
<li>Main Nav Item 5</li>
</ul>
</nav>
</header>
The problem with your code is that when you click on a submenu <li>, the click event propagates to the parent <li>, and triggers the function hiding the <ul>.
A solution could be to move the .has('ul') part of your click listener inside the callback :
$(document).ready(function() {
var subnavArrow = ['<div id="subnavArrow"></div>'];
subpull = $('header nav ul li');
submenu = $('header nav ul li ul');
submenuitems = $('header nav ul li ul li');
subpull.has('ul').prepend(subnavArrow);
$('header nav ul li').click(function(e) {
e.stopPropagation();
if ($(this).has('ul')) {
$(this).children('ul').toggle('slow');
}
});
});
This way, the listener also listens for the clicks on the submenus, and you can prevent the event from propagating to the parent with e.stopPropagation();
You can sere this solution on this JSFiddle : https://jsfiddle.net/9ejpLmLf/
Very simple code
=============================
<pre>
$(document).ready(function() {
var subnavArrow = ['<div id="subnavArrow"></div>'];
subpull = $('header nav ul li');
submenu = $('header nav ul li ul');
submenuitems = $('header nav ul li ul li');
subpull.has('ul').prepend(subnavArrow);
$('header nav ul li a').click(function() {
$(this).siblings('ul').toggle('slow');
});
});
</pre>

Progressive reveal with jQuery

I have nested unordered list.
<ul id="catalogue">
<li>List
<ul>
<li>Item 1</li>
<li>Item 2
<ul>
<li>Item 1.1</li>
<li>Item 1.2
<ul>
<li>Item 1.2.1</li>
<li>Item 1.2.2
<ul>
<li>Item 1.2.2.1</li>
</ul>
</li>
<li>Item 1.2.3</li>
</ul>
</li>
<li>Item 1.3</li>
</ul>
</li>
<li>Item 3</li>
</ul>
</li>
</ul>
At the beginning only the very top level shows, but if you click on each LI, if there's a child UL in it, it should display the next lever, and so on. If you click on the same LI again, the level below should become hidden.
$(document).ready(function () {
$('#catalogue li').each(function () {
$(this).contents().first().wrap("<span/>")
});
$('#catalogue li > span').addClass('brd');
$('ul').hide();
$('#catalogue').show();
$('#catalogue li').click(function () {
var nxt = $(this).children('ul:first')
if ($(nxt).is(":visible")) {
$(nxt).slideUp();
} else {
$(nxt).slideDown();
}
$(this).parent().show();
});
});
If a user clicks on a sibling LI and it has a child UL, that UL should show but any sibling's ones should close.
You need to stop the event from propagating to the parent. Clicking on each li will invoke its own click handler and the event will propagate to its parent li invoke its handler and so on. So you can just stop it at one level by using event.stopPropagation(). And you can use slideToggle to toggle the current state of the element.
Try:
$('#tree li').click(function (e) {
e.stopPropagation();
$(this).children('ul:first').slideToggle();
});
Demo
And if you want to slide up while clicked on its sibling then,
$('#tree li').click(function (e) {
e.stopPropagation();
var $this = $(this);
$this.children('ul:first').slideToggle().end()
.siblings().children('ul:visible').slideUp();
//Code Broken down
//$this.children('ul:first').slideToggle();
//$this.siblings().children('ul:visible').slideUp();
});
Demo

How do i select only one column when hovering over it in a drop down jQuery menu?

I need some help in finding out how to select only one column when I hover over the drop down menu. It works but all of the submenu items slide down. I want only the one I hover over to do so and then when hovering the next, the previous closes and just the next one stays opened.
Here is my HTML/CSS code and JS.
Thank's.
<head>
<title>Hover-Dropdown</title>
<link rel="stylesheet" href="css/style.css" />
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script src="js/jquery-1.10.2.js"></script>
<style>
ul{list-style: none;}
.itemList{padding: 0;margin-top: 10px;}
.column{float: left;width: 100px;margin: 0 auto;}
.menu .column a:hover{color:red;}
</style>
<script>
$(document).ready(function(){
$('.menu .column .itemList li').hide();
$('.menu .column .title').hover(function(){
$('.menu .column .itemList li').slideDown('slow');
});
$('.menu .column').mouseleave(function(){
$('.menu .column .itemList li').slideUp('slow');
});
});
</script>
</head>
<body>
<ul class="menu">
<li class="column">
<a class="title" href="#">Title 1</a>
<ul class="itemList">
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
<li>Item 4</li>
<li>Item 5</li>
</ul>
</li>
<li class="column">
<a class="title" href="#">Title 2</a>
<ul class="itemList">
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
<li>Item 4</li>
<li>Item 5</li>
</ul>
</li>
<li class="column">
<a class="title" href="#">Title 3</a>
<ul class="itemList">
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
<li>Item 4</li>
<li>Item 5</li>
</ul>
</li>
</ul>
</body>
Lets start with a simple recap of your HTML structure. Nothing wrong here, but it helps explaining the issue.
ul.menu
li.column
a.title
ul.itemList
li
li.column
a.title
ul.itemList
li
...
Now lets take a look at the changes I made to your code.
First of all I changed the hover selector from .menu .column .title to .menu .column, we could have kept it, but the code became prettier by removing it. So regard this change as purely cosmetic. :)
The BIG change you'll see is on the two lines with slideDown and slideUp. First let me explain what your code did.
$('.menu .column .itemList li').slideDown('slow');
Whenever you use $(selector).something() jQuery will start at the top of the treestructure which is your DOM, and try to look for any matching elements. In your case it will find many. In fact, every item in your submenus matches this description. And that is why every menu was shown.
$(this).find('ul li').slideDown('slow');
By changing the line to something like above you fix the start position for the search at this (if you're not sure about this and JS/jQuery you should try finding some good articles about it). In this specific case this will allways be a reference to the specific column element which is being hovered over.
Recap
$('selector').something(); //Starts a search for the selector at the document root
$(this).find('selector').something(); //Starts a search at "this" element
Think of it as global vs local search.
Try to use this:
$('.menu .column .title').hover(function(){
$(this).next('.itemList').slideDown('slow');
});

Adding a seperate class to list items parent using jquery?

I have a list with different levels of depth:
<ul id="top-level" class="top-level">
<li>Item 1</li>
<li>Item 2
<ul class="sub-menu">
<li>Sub item 1</li>
<li>Sub item 2</li>
<li>Sub item 3
<ul class="sub-menu">
<li>Subsub item 1</li>
<li>Subsub item 2</li>
</ul>
</li>
<li>Sub item 4</li>
</ul>
</li>
<li>Item 3</li>
</ul>
I am using the following jquery script to add a class to the parents:
$("ul li ul").parent().addClass("menuparent");
Is there a way to add this class only to the top level parent li's and a different class for all other (deeper) parent li's?
Just use the > selector from your top level ul.
Based on your current selector:
$("ul.top-level > li > ul").parent().addClass("menuparent");
Or for li only:
$("ul.top-level > li").parent().addClass("menuparent");
For top level lis
$("#top-level > li").addClass("menuparent");
and for lower level li
$("#top-level li li").addClass("someotherclass");
If I understand correctly, people are not giving you answers for locating the deeper parent li's, here's my take:
$("ul.top-level > li > ul").find('li > ul').parent().addClass("deeper-parent-li");

sub nav not directing to page (jquery)

I have basic markup for a drop down nav, nested lists.
The user will click on the top nav item, which will open up the sub nav, but my sub nav links aren't working.
It is in a CMS so I must have the links for the placeholder pages there.
Markup:
<ul class="navtop">
<li>Who
<ul>
<li>Sub Item 1</li>
<li>Sub Item 2</li>
<li>Long Sub Item 3</li>
<li>Sub Item 4</li>
</ul>
</li>
<li>What
<ul>
<li>Sub Item 1</li>
<li>Sub Item 2</li>
<li>Long Sub Item 3</li>
<li>Sub Item 4</li>
</ul>
</li>
</ul>
Javascript:
$(".navtop li").click(function(){
$(this).toggleClass("show");
$(this).siblings(".show").toggleClass("show");
return false;
});
css:
#headernav .navtop li.show ul
{
display: block;
}
I tried adding a 'return true' for $(".navtop li ul li a") but it didn't work.
Suggestions?
Why are you return false to the LI click? I believe that's the problem.
If you take that out, everything should work fine.
If that doesn't work, bear in mind you're attaching the click event to every LI instead of just the top level LIs. Try this instead:
$(".navtop > li").click(function(){
$(this).toggleClass("show");
$(this).siblings(".show").toggleClass("show");
});
Turns out this worked:
$(".navtop > li > a").click(function(){
$(this).parent('li').toggleClass("show");
$(this).parent('li').siblings(".show").toggleClass("show");
return false;
});

Categories

Resources