Vertical toggle menu 3rd level parent stay opened. jQuery - javascript

I am working on a simple vertical toggle menu but having trouble leaving the first drop level opened when its sub level is clicked. For less confusion here is fiddle , click on "Products" than on "Sites" and products will close.
But if you click on Products and than on Services it does what is needed
which is , close other subs when one is opened.
$('.vtoggle li').each(function(el) {
$(this).find('a').first().attr('href', 'javascript:;').addClass('vtoggler');
});
$('ul.vtoggle > li:has(ul)').addClass("inactive");
$('ul.vtoggle > li:has(ul) ul').css('display', 'none');
$('.vtoggler').click(function() {
var checkElement = $(this).next();
$('.vtoggle li').removeClass('active');
$(this).closest('li').addClass('active').removeClass("inactive");
if ((checkElement.is('ul')) && (checkElement.is(':visible'))) {
$(this).closest('li').removeClass('active').addClass('inactive');
checkElement.slideUp('normal');
}
if ((checkElement.is('ul')) && (!checkElement.is(':visible'))) {
$('ul.vtoggle ul:visible').slideUp('normal');
checkElement.slideDown('normal');
}
if (checkElement.is('ul')) {
return false;
} else {
return true;
}
});
body {
background: #fff;
}
.vertical ul {
list-style-type: none;
padding: 0;
margin: 0;
display: block;
position: relative;
}
.vertical li {
list-style-type: none;
padding: 0;
margin: 0;
display: block;
float: none;
position: relative;
}
.vertical li a {
display: block;
height: 45px;
line-height: 45px;
padding: 0 10px;
border: 1px solid rgba(0, 0, 0, 0);
border-bottom-color: #eee;
}
/* sub menu */
.vertical ul ul {
display: none;
position: relative;
padding: 0 0 0 20px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<nav class="vertical">
<ul class="vtoggle">
<li>Home</li>
<li>Services +
<ul>
<li>Service 1</li>
<li>Service 2</li>
<li>Service 3</li>
</ul>
</li>
<li>Products +
<ul>
<li>Widgets</li>
<li>
Sites +
<ul>
<li>Site 1</li>
<li>Site 2</li>
</ul>
</li>
<li>Gadgets +
<ul>
<li>Gadget 1</li>
<li>Gadget 2</li>
</ul>
</li>
</ul>
</li>
<li>Contact</li>
</ul>
</nav>

A soution can be to wrap line into:
var lastUl = $('ul.vtoggle ul:visible:last');
if (lastUl.find(this).length == 0) {
$('ul.vtoggle ul:visible').each(function() {
if ($(this).find(checkElement).length == 0) {
$(this).slideUp('normal');
}
})
}
The snippet:
$(function () {
$('.vtoggle li').each(function (el) {
$(this).find('a').first().attr('href', 'javascript:;').addClass('vtoggler');
});
$('ul.vtoggle > li:has(ul)').addClass("inactive");
$('ul.vtoggle > li:has(ul) ul').css('display', 'none');
$('.vtoggler').click(function (e) {
var checkElement = $(this).next();
$('.vtoggle li').removeClass('active');
$(this).closest('li').addClass('active').removeClass("inactive");
if ((checkElement.is('ul')) && (checkElement.is(':visible'))) {
$(this).closest('li').removeClass('active').addClass('inactive');
checkElement.slideUp('normal');
}
if ((checkElement.is('ul')) && (!checkElement.is(':visible'))) {
var lastUl = $('ul.vtoggle ul:visible:last');
if (lastUl.find(this).length == 0) {
$('ul.vtoggle ul:visible').each(function() {
if ($(this).find(checkElement).length == 0) {
$(this).slideUp('normal');
}
})
}
checkElement.slideDown('normal');
}
if (checkElement.is('ul')) {
return false;
} else {
return true;
}
});
});
body {
background: #fff;
}
.vertical ul {
list-style-type: none;
padding: 0;
margin: 0;
display: block;
position: relative;
}
.vertical li {
list-style-type: none;
padding: 0;
margin: 0;
display: block;
float: none;
position: relative;
}
.vertical li a {
display: block;
height: 45px;
line-height: 45px;
padding: 0 10px;
border: 1px solid rgba(0, 0, 0, 0);
border-bottom-color: #eee;
}
/* sub menu */
.vertical ul ul {
display: none;
position: relative;
padding: 0 0 0 20px;
}
<script src="https://code.jquery.com/jquery-1.12.4.min.js"></script>
<nav class="vertical">
<ul class="vtoggle">
<li>Home</li>
<li>Services +
<ul>
<li>Service 1</li>
<li>Service 2</li>
<li>Service 3</li>
</ul>
</li>
<li>Products +
<ul>
<li>Widgets</li>
<li>
Sites +
<ul>
<li>Site 1</li>
<li>Site 2</li>
</ul>
</li>
<li>Gadgets +
<ul>
<li>Gadget 1</li>
<li>Gadget 2</li>
</ul>
</li>
</ul>
</li>
<li>Contact</li>
</ul>
</nav>

Related

Custom CSS Navigation dropdown

Currently on my site when I have too many links, the link falls down below the navigation. See my example: https://jsfiddle.net/cn6z13n1/
Is it possible instead to have a More Links list item at the far right which will have a dropdown populated with links?
.toolkit_nav {
background:#dfdfdf;
width:100%;
height:40px;
padding:0;
}
.toolkit_nav ul {
margin:0;
}
.toolkit_nav ul .page_item {
display:inline-block;
line-height:40px;
list-style-type:none;
margin:0px;
padding:0 20px;
}
.toolkit_nav ul .page_item:first-child {
margin-left:0;
padding-left:0;
}
.page_item:hover, .current_page_item {
background:grey;
}
.page_item a {
color:black;
font-size: 0.9em;
font-weight: 400;
text-decoration:none;
}
<nav class="toolkit_nav">
<div class="row">
<div class="medium-12 columns">
<ul>
<li class="page_item page-item-1035 current_page_item">Introduction</li>
<li class="page_item page-item-1039">Digital Landscapes</li>
<li class="page_item page-item-1039">Link 4</li>
<li class="page_item page-item-1039">Link 3</li>
<li class="page_item page-item-1039">Link 2</li>
<li class="page_item page-item-1039">Link 1</li>
<li class="page_item page-item-1039">Link 5</li>
</ul>
</div>
</div>
</nav>
You would need to do this in js i suggest something like this
get the width of the row (max width for nav)
loop through the li elements and sum up there width (+ remember to add the width of a "more" element here
when sum of width > width of nav element hide the elements
add js to your "more" button which shows the hidden elements
Following code is not tested but should give you an idea:
var maxWidth = $('#nav').width();
var moreWidth = $('#more').width(); // li "more" element
var sumWidth = moreWidth;
$('#nav li').each(function() {
sumWidth += $(this).width();
if(sumWidth > maxWidth) {
$(this).addClass('hide'); // add css for hide class
}
});
$('#more').on('click', function() {
$('#nav .hide').fadeIn(100);
// You will need more code here to place it correctly, maybe append the elements in an container
});
Here an example with your fiddle:
https://jsfiddle.net/cn6z13n1/3/
Note: this is just a rough draft, you might to calc paddings etc. to make this work rly good
Edit: updated example with $(window).resize() function
https://jsfiddle.net/cn6z13n1/6/
You'll need to change you HTML slightly but this will work.
.toolkit_nav {
background: #dfdfdf;
width: 100%;
height: 40px;
padding: 0;
}
.toolkit_nav ul {
margin: 0;
}
.toolkit_nav ul .page_item {
display: inline-block;
line-height: 40px;
list-style-type: none;
margin: 0px;
padding: 0 20px;
}
.toolkit_nav ul .page_item:first-child {
margin-left: 0;
padding-left: 0;
}
.page_item:hover,
.current_page_item {
background: grey;
}
.page_item a {
color: black;
font-size: 0.9em;
font-weight: 400;
text-decoration: none;
}
/* NEW STUFF */
.sub-nav,
.sub-nav li {
box-sizing: border-box;
}
.more {
position: relative;
}
.more>ul {
display: none;
position: absolute;
left: 0;
top: 100%;
padding: 0
}
.more:hover>ul {
display: block;
}
.more>ul>li {
display: block;
width: 100%;
clear: both;
text-align: center;
}
.toolkit_nav ul.sub-nav .page_item:first-child {
padding: 0 20px;
}
<nav class="toolkit_nav">
<div class="row">
<div class="medium-12 columns">
<ul>
<li class="page_item page-item-1035 current_page_item">Introduction
</li>
<li class="page_item page-item-1039">Digital Landscapes
</li>
<li class="page_item page-item-1039">Link 4
</li>
<li class="page_item page-item-1039">Link 3
</li>
<li class="page_item page-item-1039">Link 2
</li>
<li class="page_item page-item-1039 more">More...
<ul class="sub-nav">
<li class="page_item page-item-1039">Link 1
</li>
<li class="page_item page-item-1039">Link 5
</li>
</ul>
</li>
</ul>
</div>
</div>
</nav>

How to remove jquery cache on hovered item

i'm not sure if i gave the right term. I'm having an issue on how to remove the cache on the hovered item.
Html
<div class="gallery-nav">
<ul>
<li> 01</li>
<li> 02</li>
<li> 03</li>
<li> 04</li>
<li> 05</li>
<li> 06</li>
<li> 07</li>
<li> 08</li>
<li> 09</li>
<li> 10</li>
<li> 11</li>
<li> 12</li>
</ul>
<div class="clear"></div>
</div>
Javascript
function growLine(e) {
e.find('span').stop(false,true).animate({
width: 22
}, 400);
}
function shrinkLine(e) {
e.find('span').stop(false,true).animate({
width: 0
}, 400);
}
$('.gallery-nav li').each(function() {
$(this).append('<span />');
});
$('.gallery-nav li:first-child').addClass('active');
$('.gallery-nav li').hover(function() {
if( !$(this).hasClass('active') ) {
growLine($(this) );
}
}, function() {
if( !$(this).hasClass('active') ) {
shrinkLine( $(this) );
}
});
$('.gallery-nav li a').click( function () {
var allList = $('.gallery-nav li');
var e = $(this);
allList.removeAttr('class');
e.parent().addClass('active');
});
jsFiddle
There is a line below the numbers when hovered.
The problem is the line is not removed once i click on other numbers.
This works but only once.
You are doing animation to set width of span(which is inside li) equal to width=22 and adding classactive to li. You just have to revert this effect.
You need to modify your click event handler so that to set width=0px for span and active class from the li having class="active", see below code
$('.gallery-nav li a').click( function () {
var e = $(this);
$('li.active').find('span').css('width','0px');
$('li.active').removeClass('active');
e.parent().addClass('active');
});
DEMO
try this: Jsfiddle
$('.gallery-nav li:first-child').addClass('active');
$('.gallery-nav li').click( function () {
$(this).addClass('active').siblings().removeClass('active');
});
.gallery-nav ul {
margin: 0;
padding: 0 ;
list-style: none;
}
.gallery-nav li {
float: left;
margin: 0 7px;
}
.gallery-nav li a {
display: block;
position: relative;
text-transform: uppercase;
font: 300 19px 'Lato', sans-serif;
color : #000;
text-decoration: none;
}
.gallery-nav li a:before {
content: '';
position: absolute;
bottom: -2px;
left: 0;
background: red;
height: 1px;
width: 0px;
transition: width .3s ease
}
.gallery-nav li.active > a,
.gallery-nav li:hover > a {
font-weight: 700;
}
.gallery-nav li:hover a:before,
.gallery-nav li.active a:before {
width: 22px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="gallery-nav">
<ul>
<li> 01</li>
<li> 02</li>
<li> 03</li>
<li> 04</li>
<li> 05</li>
<li> 06</li>
<li> 07</li>
<li> 08</li>
<li> 09</li>
<li> 10</li>
<li> 11</li>
<li> 12</li>
</ul>
<div class="clear"></div>
</div>

Accordion with multiple links

I'm taking this CSS-Tricks article and converting it to a UL > LI instead of a DT > DD approach. I just want the pink box to reveal the sub-links when clicked.
For some reason though I cannot get it working. I've created a jsFiddle of it here (click the pink box):
//Accordion
(function($) {
var allPanels = $('ul.sub-level').hide();
$('.click-me').click(function() {
allPanels.slideUp();
alert('slide up');
// Problem line
$(this).parent().next().slideDown();
return false;
});
})(jQuery);
ul { list-style: none; padding:0; margin:0; width: 400px; }
ul li { position:relative; background: #fafafa; margin-bottom:3px; height:20px; }
ul li > ul { margin-left: 30px; background: #e3e3e3; }
.click-me { display:block; width: 20px; height: 20px; position: absolute; top:0; right:0; background: #e4f; cursor: pointer;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul>
<li>Link somewhere</li>
<li>Link somewhere</li>
<li class="test">
Link somewhere
<!-- I want to reveal accordion using this span tag -->
<span class="click-me"></span>
<!-- /end -->
<ul class="sub-level">
<li>Link 1</li>
<li>Link 2</li>
<li>Link 3</li>
<li>Link 4</li>
</ul>
<li>Link somewhere</li>
</li>
</ul>
http://jsfiddle.net/ndczc728/1/
The problem line is this (I think):
// Problem line
$(this).parent().next().slideDown();
Anyone?
You don't need to use parent. Also you have to remove fixed height from li elements:
//Accordion
(function($) {
var allPanels = $('ul.sub-level').hide();
$('.click-me').click(function() {
allPanels.slideUp();
// Problem line
$(this).next().slideDown();
return false;
});
})(jQuery);
ul {
list-style: none;
padding: 0;
margin: 0;
width: 400px;
}
ul li {
position: relative;
background: #fafafa;
margin-bottom: 3px;
}
ul li > ul {
margin-left: 30px;
background: #e3e3e3;
}
.click-me {
display: block;
width: 20px;
height: 20px;
position: absolute;
top: 0;
right: 0;
background: #e4f;
cursor: pointer;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul>
<li>Link somewhere
</li>
<li>Link somewhere
</li>
<li class="test">
Link somewhere
<!-- I want to reveal accordion using this span tag -->
<span class="click-me"></span>
<!-- /end -->
<ul class="sub-level">
<li>Link 1
</li>
<li>Link 2
</li>
<li>Link 3
</li>
<li>Link 4
</li>
</ul>
<li>Link somewhere
</li>
</li>
</ul>

how to hide dropdown menu if i click body any element?

How to close my DropDown menu if i click body element of outside dropdown menu .
Please give me suggestion .
My code is
$(document).ready(function(){
$(document).on('click', '.top-nav-head>li>a', function(){
$(this).siblings('ul').toggle().closest('.top-nav-head>li').siblings('li').find('ul').hide();
});
});
.top-nav-head{
list-style-type: none;
padding: 0;
margin: 0;
background:blue;
float: left;}
.top-nav-head>li{
float: left;
position: relative;
}
.top-nav-head>li > a{
color: #000;
padding: 0 10px;
display: block;
line-height: 40px;
font-size: 14px;
}
.top-nav-head>li > ul{
position: absolute;
display: none;
top: 100%;
left: 0;
min-width: 140px;
right: 0;
list-style-type: none;
padding: 5px 0 5px 0;
margin: 0;
background-color: red;
}
.top-nav-head>li > ul>li{
display: block;
}
.top-nav-head>li > ul>li > a{
display: block;
color:#white;
padding: 5px 10px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<ul class="top-nav-head">
<li>Home</li>
<li class="active">
Admin Module
<ul>
<li><a ui-sref="av-kw-questions.empty">Questions</a></li>
<li><a ui-sref="av-wbs">WBS Elements</a></li>
<li><a ui-sref="av-lbp">Lookback planning</a></li>
<li>Form</li>
<li>Plan Component</li>
</ul>
</li>
<li>
Project Management
<ul>
<li>Link 1</li>
<li>Link 2</li>
<li>Link 3</li>
<li>Link 4</li>
<li>Link 5</li>
</ul>
</li>
</ul>
You could attach an event handler to the document that will hide your drop down menus.
You would the need to stop the event bubbling when clicking on the menu items themselves:
$(document).ready(function () {
$(document).on('click', function () {
$('.top-nav-head > li > ul').hide();
});
$(document).on('click', '.top-nav-head>li>a', function (e) {
e.stopPropagation();
$(this).siblings('ul').toggle().closest('.top-nav-head>li').siblings('li').find('ul').hide();
});
});
JSFiddle
This will check if you have clicked on the element, just set your selector ("most" parent) and "hide" functionality:
$(document).mouseup(function (e)
{
var your_element = $('#your_element');
if(container.has(e.target).length === 0)
{
//hide your element
}
});

How to reverse the direction of a suckerfish menu (drop-up)

I have a navigation bar at the bottom of my page rather than at the top. I am trying to implement a "drop-up" suckerfish menu. I want to do it with as little javascript as possible. My current code is as follows and works fine as a drop-down menu. Is there a way to reverse it?
Here is my code:
<style type="text/css">
#nav, #nav ul {
padding: 0;
margin: 0;
list-style: none;
}
#nav a {
display: block;
width: 10em;
}
#nav li {
float: left;
width: 10em;
background: #000000;
}
#nav li ul {
position: absolute;
left: -999em;
}
#nav li: hover ul {
left: auto;
}
#nav li:hover ul, #nav li.sfhover ul {
left: auto;
}
</style>
<script type="text/javascript">
sfHover = function() {
var sfEls = document.getElementById("nav").getElementsByTagName("LI");
for (var i=0; i<sfEls.length; i++) {
sfEls[i].onmouseover=function() {
this.className+=" sfhover";
}
sfEls[i].onmouseout=function() {
this.className=this.className.replace(new RegExp(" sfhover\\b"), "");
}
}
}
if (window.attachEvent) window.attachEvent("onload", sfHover);
</script>
<ul id="nav">
<li>Home</li>
<li>About Us
<ul>
<li>Who We Are</li>
<li>What We Believe</li>
<li>Our Pastors</li>
</ul>
</li>
<li>Ministries
<ul>
<li>Victory Kids (VC3)</li>
<li>Victory Youth</li>
<li>Connect Groups</li>
<li>S.O.A.P</li>
<li>Victory Group</li>
</ul>
</li>
<li>Connect
<ul>
<li>Contact Us</li>
<li>Social Networks</li>
<li>Blogs</li>
</ul>
</li>
<li>Media
<ul>
<li>Sermon Podcasts</li>
<li>Videos</li>
<li>Images</li>
</ul>
</li>
<li>Giving
<ul>
<li>Help Support</li>
<li>Ministries We Support</li>
<li>2011 Financial Report</li>
</ul>
</li>
<li>Resources</li>
</ul>
All help is appreciated. Thanks!
<style type="text/css">
#nav, #nav ul {
padding: 0;
margin: 0;
list-style: none;
bottom:0px;
position:absolute;
}
#nav a {
display: block;
width: 10em;
}
#nav li {
float: left;
width: 10em;
background: #000000;
}
#nav li ul {
position: absolute;
left: -999em;
bottom:20px;
}
#nav li: hover ul {
left: auto;
}
#nav li:hover ul, #nav li.sfhover ul {
left: auto;
}
</style>
<script type="text/javascript">
sfHover = function() {
var sfEls = document.getElementById("nav").getElementsByTagName("LI");
for (var i=0; i<sfEls.length; i++) {
sfEls[i].onmouseover=function() {
this.className+=" sfhover";
}
sfEls[i].onmouseout=function() {
this.className=this.className.replace(new RegExp(" sfhover\\b"), "");
}
}
}
if (window.attachEvent) window.attachEvent("onload", sfHover);
</script>
<ul id="nav">
<li>Home</li>
<li>About Us
<ul>
<li>Who We Are</li>
<li>What We Believe</li>
<li>Our Pastors</li>
</ul>
</li>
<li>Ministries
<ul>
<li>Victory Kids (VC3)</li>
<li>Victory Youth</li>
<li>Connect Groups</li>
<li>S.O.A.P</li>
<li>Victory Group</li>
</ul>
</li>
<li>Connect
<ul>
<li>Contact Us</li>
<li>Social Networks</li>
<li>Blogs</li>
</ul>
</li>
<li>Media
<ul>
<li>Sermon Podcasts</li>
<li>Videos</li>
<li>Images</li>
</ul>
</li>
<li>Giving
<ul>
<li>Help Support</li>
<li>Ministries We Support</li>
<li>2011 Financial Report</li>
</ul>
</li>
<li>Resources</li>
</ul>
Try this without additional JS

Categories