Jquery slideUp doesn't work at first click - javascript

I've created myself a accordion menu, but I've got a problem. When I click for the first time on 'li' element slideUp doesn't work.
$(document).ready(function() {
$('#menu ul li a').click(function(e) {
e.preventDefault();
if ($(this).parent().hasClass('active')) {
if ($(this).next().is(':visible')) {
$(this).next().slideUp();
$(this).parent().removeClass('active');
} else {
$(this).next().slideDown();
}
} else {
$('#menu ul li').each(function() {
$(this).removeClass('active');
});
$('#menu ul li ul').slideUp();
$(this).next().slideDown();
$(this).parent().addClass('active');
}
});
});
#menu,
#menu ul,
#menu li,
#menu a {
margin: 0;
padding: 0;
border: 0;
list-style: none;
font-weight: normal;
text-decoration: none;
line-height: 1;
font-family: 'Open Sans', sans-serif;
font-size: 14px;
position: relative;
}
#menu a {
line-height: 1.3;
}
#menu > ul > li {
margin: 0;
}
#menu > ul > li:last-child {
margin: 0;
}
#menu > ul > li > a {
font-size: 15px;
display: block;
color: #ffffff;
text-shadow: 0 1px 1px #000;
padding: 5px;
}
#menu > ul > li > a > span {
display: block;
padding: 6px 10px;
font-weight: bold;
}
#menu > ul > li > a:hover {
text-decoration: none;
background: #0074a2 url('../img/icons/menuActive.png') no-repeat 101%;
}
#menu > ul > li.active {
border-bottom: none;
}
#menu > ul > li.active > a {
background: #0074a2 url('../img/icons/menuActive.png') no-repeat 101%;
color: #fff;
text-shadow: 0 1px 1px #000;
}
/* Sub menu */
#menu ul ul {
padding: 5px 12px;
display: none;
background: #333333;
}
#menu ul ul li {
padding: 3px 0;
}
#menu ul ul a {
display: block;
color: #fff;
font-size: 13px;
font-weight: bold;
padding: 10px 0;
}
#menu ul ul a:hover {
color: #0074a2;
}
#menu ul li.active ul {
display: block;
}
#menu ul li img {
float: left;
margin: -2px 4px 0 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="menu">
<ul>
<li class='has-sub active'><a href='#'><span>AAA</span></a>
<ul>
<li><a href='#'><span>AAA_1</span></a></li>
<li><a href='#'><span>AAA_2</span></a></li>
<li><a href='#'><span>AAA_3</span></a></li>
</ul>
</li>
<li class='has-sub'><a href='#'><span>BBB</span></a>
<ul>
<li><a href='#'><span>BBB_1</span></a></li>
<li><a href='#'><span>BBB_2</span></a></li>
</ul>
</li>
<li class='has-sub last'><a href='#'><span>CCC</span></a>
<ul>
<li><a href='#'><span>CCC_1</span></a></li>
<li><a href='#'><span>CCC_2</span></a></li>
<li><a href='#'><span>CCC_3</span></a></li>
<li><a href='#'><span>CCC_4</span></a></li>
</ul>
</li>
</ul>
</div>
Here is my simple code typed in jsfiddle.
jsfiddle
Could anyone tell me where is an error and how to solve it ?
Thanks !

The state of the html goes like this:
1. From start: <ul>
2. After you click once: <ul style="display: none;">
3. After you click it again: <ul style="display: block;">
Now I'm not that great when it comes to css, but if you keep track of the dynamic css which goes on when you press it, then you'll know what attributes you are missing on your styling.

The problem is active class has been removed before finishing slideUp animation. Use setTimeout function like following.
setTimeout(function(){
$(this).parent().removeClass('active')
}, 0);
You can increase time if you need.
Update:
I think your selector should be.
$('#menu > ul > li > a')
instead of
$('#menu ul li a')

Related

How to change + to - when parent menu is clicked [duplicate]

This question already has answers here:
Selecting and manipulating CSS pseudo-elements such as ::before and ::after using javascript (or jQuery)
(26 answers)
Closed 3 years ago.
How to change + to - when menu parent menu item is clicked. i was looking to target ::after element using jquery but i cant find way to target pseudo element using jquery
I want to change below css to when perent menu is clicked
.ir-nav-w > ul li::after {
/* padding-left: 10px; */
text-transform: uppercase;
content: "-";
position: absolute;
left: 15px;
top: 4px;
line-height: 30px;
font-size: 20px;
z-index: 0;
}
Fiddle code
$(".nav-w > ul > li > a").click(function() {
$(this).next().slideToggle();
});
//open active list
$('.nav-w ul li').children().has('.active-menu').css('display', 'block');
// compare url with nav url to show active url
$(function() {
//var url = window.location.href;
var url = window.location.pathname;
var pgurl = window.location.href.substr(
window.location.href.lastIndexOf("/") + 1
);
$(".nav-w ul li a").each(function() {
if ($(this).attr("href") == url || $(this).attr("href") == "") {
$(this).addClass("active-menu");
}
});
console.log("url : " + window.location.pathname);
});
.nav-w a {
color: black;
padding: 10px 15px;
padding-left: 35px;
text-decoration: none;
display: block;
border-bottom: 1px solid #f1f1f1;
font-size: 12px;
font-weight: 600;
/* color: #178B43 !important; */
color: #757575;
}
/* ul inside content area*/
.nav-w ul {
margin-left: 0px;
list-style-type: none;
margin-bottom: 0px;
}
.nav-w ul li {
/*padding-left: 10px;*/
text-transform: uppercase;
position: relative;
width: 100%;
}
/* ol inside content area*/
.nav-w>ul {
padding-left: 0px;
padding-right: 0px;
}
.nav-w ul>li ul {
padding-left: 0px;
padding-right: 0px;
display: none;
}
.active-menu {
color: red !important;
}
.nav-w>ul li::after {
text-transform: uppercase;
content: "+";
position: absolute;
left: 15px;
top: 4px;
line-height: 30px;
font-size: 20px;
z-index: 0;
}
.nav-w>ul li ul li::after {
text-transform: uppercase;
content: "";
position: absolute;
left: 0px;
top: 5px;
line-height: 32px;
font-size: 20px;
z-index: 0;
}
.nav-w ul li ul li a {
padding-left: 45px;
}
.nav-w a:hover {
background: #f5f5f5;
border-left: 2px solid #178B43;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="nav-w">
<ul class="">
<li>Share Information
<ul class="" style="display: none;">
<li>Share Overview</li>
<li>Share Graph </li>
<li>Investement Calculator</li>
<li>Historical Share Prices</li>
</ul>
</li>
<li>Financial Information
<ul class="" style="display: none;">
<li>Earning Releases</li>
<li>Financial Statements</li>
<li><a href="/investor-relations/financial-information/presentation">Presentation
</a></li>
<li><a href="/investor-relations/financial-information/quarterly-key-figures">Quarterly Key Figures
</a></li>
<li><a href="/investor-relations/financial-information/annual-key-figures">Annual Key Figures
</a></li>
</ul>
</li>
</ul>
</div>
The way I would do it is to add a class to the parent menu after it is clicked, such as open.
And then in your css you could add a special modifier:
.nav-w > ul li.open::after {
content: "-"
}
And when it is click again, remove the class open.
You can't manipulate :after, because it's not technically part of the DOM and therefore is inaccessible by any JavaScript. But you can add a new class with a new ::after specified.
Add this to your code:
// JS
const $listItems = $('.ir-nav-w > ul li');
$listItems.onClick(
$listItems.removeClass('closed');
this.addClass('closed')
);
// CSS
.ir-nav-w > ul li.closed::after {
content: "+";
}
Trick is to add css:
.nav-w > ul li.selected::after {
content: "-";
}
and toggle selected class on click:
$(".nav-w > ul > li > a").click(function () {
$(this).parent().toggleClass("selected");
$(this).next().slideToggle();
});
$(".nav-w > ul > li > a").click(function () {
$(this).parent().toggleClass("selected");
$(this).next().slideToggle();
});
//open active list
$('.nav-w ul li').children().has('.active-menu').css('display', 'block');
.nav-w a {
color: black;
padding: 10px 15px;
padding-left: 35px;
text-decoration: none;
display: block;
border-bottom: 1px solid #f1f1f1;
font-size: 12px;
font-weight: 600;
/* color: #178B43 !important; */
color: #757575;
}
/* ul inside content area*/
.nav-w ul{
margin-left: 0px;
list-style-type:none;
margin-bottom:0px;
}
.nav-w ul li{
/*padding-left: 10px;*/
text-transform:uppercase;
position:relative;
width:100%;
}
/* ol inside content area*/
.nav-w > ul {
padding-left: 0px;
padding-right: 0px;
}
.nav-w ul > li ul {
padding-left: 0px;
padding-right: 0px;
display:none;
}
.active-menu {
color: red !important;
}
.nav-w > ul li::after {
text-transform: uppercase;
content: "+";
position: absolute;
left: 15px;
top: 4px;
line-height: 30px;
font-size: 20px;
z-index: 0;
}
.nav-w > ul li.selected::after {
content: "-";
}
.nav-w > ul li ul li::after {
text-transform: uppercase;
content: "";
position: absolute;
left: 0px;
top: 5px;
line-height: 32px;
font-size: 20px;
z-index: 0;
}
.nav-w ul li ul li a {
padding-left:45px;
}
.nav-w a:hover {
background: #f5f5f5;
border-left: 2px solid #178B43;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="nav-w">
<ul class="">
<li>Share Information
<ul class="" style="display: none;">
<li>Share Overview</li>
<li>Share Graph </li>
<li><a href="/investor-relations/share-nformations/investor-calculator/" >Investement Calculator</a></li>
<li>Historical Share Prices</li>
</ul>
</li>
<li>Financial Information
<ul class="" style="display: none;">
<li>Earning Releases</li>
<li>Financial Statements</li>
<li><a href="/investor-relations/financial-information/presentation">Presentation
</a></li>
<li><a href="/investor-relations/financial-information/quarterly-key-figures">Quarterly Key Figures
</a></li>
<li><a href="/investor-relations/financial-information/annual-key-figures">Annual Key Figures
</a></li>
</ul>
</li>
</ul>
</div>
It's not actually possible to target :after, because it isn't part of the DOM and can't be accessed through JavaScript code. This isn't a jQuery limitation.
You could just set a class on the element itself, and change the :after rule when the class is set, i.e.:
.nav-w > ul li.active::after
{
content: "-"
}
Add active class to the anchors' parent:
$(".nav-w > ul > li a").click(function () {
$(this).next().slideToggle();
$(this).parent().toggleClass('active');
});
And replace ::after on the active class:
.nav-w > ul li.active::after {
content: '-'
}
You can do with :after prop.
You can do something like this
.li-item::after{
content: "+";
}
.li-item-minus::after{
content: "-" !important;
}
While in jQuery - you can toggle class .li-item-minus on click of each list item
jQuery(".naw-v ul li").on("click", function(){
jQuery(this).toggleClass("li-item-minus");
});
Which means - on click of this li element, you toggleClass li-item-minus which has different content form main one.

Why are the anchors in my submenu returning false?

I am writing a jquery dropdown script for my navigation submenus. I have return false on the top level anchors but the problem is that this is also applying to the anchors in the submenus. My script also adds chevrons to the top level links that have submenus but those are also being added to the submenu links. What am I doing wrong? Here is a jsFiddle. Thanks for your time.
<div class="nav-outter">
<nav>
<ul>
<li>Home</li>
<li class="has-submenu">Services
<ul>
<li>Web Development</li>
<li>Photography</li>
<li>Multimedia</li>
</ul>
</li>
</ul>
</nav>
</div>
$(document).ready(function() {
$('nav > ul > li.has-submenu').each(function() {
$(this).find('a:first-child').each(function() {
$(this).append('<i class="fa fa-chevron-down"></i>');
$(this).on('click', function(e) {
e.preventDefault();
$(this).parent().find('ul').each(function() {
if ($(this).hasClass('active')) {
$(this).removeClass('active')
.slideUp(300);
} else {
$(this).addClass('active')
.slideDown(300);
}
});
});
});
});
});
.nav-outter {
position: relative;
z-index: 1;
}
nav > ul {
list-style: none;
}
nav > ul > li {
display: inline-block;
}
nav > ul > li > a {
padding: 3px 15px;
font-size: 1.2em;
color: #2c3e50;
text-decoration: none;
}
nav > ul > li > ul {
display: none;
position: absolute;
z-index: 5;
list-style: none;
border: 1px solid #FC4349;
border-bottom: 0px;
margin-left: 0px;
padding-left: 0px;
margin-top: 3%;
}
nav > ul > li > ul > li {
border-bottom: 1px solid #FC4349;
}
nav > ul > li > ul > li > a {
display: block;
padding: 15px 25px 15px 10px;
text-align: left;
background: #fff;
color: #FC4349;
text-decoration: none;
}
The find('a:first-child') is going to include every first child which is all of the links since each one is a first-child
A simpler approach would be just target the children of has-submenu and remove one each
$('nav > ul > li.has-submenu').children('a').each(function() {
$(this).append('<i class="fa fa-chevron-down"></i>');
$(this).on('click', function(e) {
.....
Or using your code if you had used find('a:first') it would have worked since you would be targeting only the first <a> in each of those class

Why is the sub-menu in this accordion menu not staying open?

I adapted a menu from CSS MenuMaker, and I've been hunting for why it behaves differently. It is here. When you click on the menu item, the sub-menu opens, but if the mouse remains over the clicked menu item, the rest doesn't move down to make room, and the sub-menu doesn't use the styling it is supposed to. Instead it uses the styling of a top-level menu item.
HTML
<div class="col-2 col-m-2 accordian darkYellow roundLeft">
<p class="title">Melt-in-Place Station (MIP)
</p>
<ul>
<li class="has-sub"><a><span>Reference Docs</span></a>
<ul>
<li><a href="http://ntrs.nasa.gov/archive/nasa/casi.ntrs.nasa.gov/20150000305.pdf">
<span>Melted regolith construction</span></a></li>
</ul>
</li>
<li class="has-sub"><a><span>Forum Threads</span></a></li>
<li class="has-sub"><a><span>Models</span></a></li>
</ul>
</div>
CSS
.accordian,
.accordian ul,
.accordian li,
.accordian a {
margin: 0;
padding: 0;
border: 0;
list-style: none;
text-decoration: none;
line-height: 1;
font-size: 1em;
position: relative;
color: yellow;
}
p.title {
font-weight: 600;
padding: 16px 6px;
}
.accordian a {
line-height: 1.3;
cursor: pointer;
}
.accordian {
font-weight: 400;
color: rgba(255, 255, 0, 1);
text-align: right;
}
.accordian > ul > li {
margin: 0 0 2px 0;
}
.accordian > ul > li:last-child {
margin: 0;
}
.accordian > ul > li > a {
font-size: 1.1em;
display: block;
background: rgba(50, 50, 50, 0.6);
}
.accordian > ul > li > a > span {
display: block;
padding: 6px 10px;
}
.accordian > ul > li > a:hover {
text-decoration: none;
}
.accordian > ul > li.active {
border-bottom: none;
}
.accordian > ul > li.active > a {
background: #333;
}
.accordian > ul > li.has-sub > a span {
background: url(http://www.moonwards.com/img/iconPlus.png) no-repeat left center;
}
.accordian > ul > li.has-sub.active > a span {
background: url(http://www.moonwards.com/img/iconMinus.png) no-repeat left center;
}
/* Sub menu */
.accordian ul ul {
padding: 5px 12px;
display: none;
}
.accordian ul ul li {
padding: 3px 0;
}
.accordian ul ul a {
display: block;
font-size: 0.9em;
font-weight: 400italic;
}
jQuery
( function( $ ) {
$( document ).ready(function() {
$('.accordian > ul > li > a').click(function() {
$('.accordian li').removeClass('active');
$(this).closest('li').addClass('active');
var checkElement = $(this).next();
if((checkElement.is('ul')) && (checkElement.is(':visible'))) {
$(this).closest('li').removeClass('active');
checkElement.slideUp('normal');
}
if((checkElement.is('ul')) && (!checkElement.is(':visible'))) {
$('.accordian ul ul:visible').slideUp('normal');
checkElement.slideDown('normal');
}
if($(this).closest('li').find('ul').children().length == 0) {
return true;
} else {
return false;
}
});
});
} )( jQuery );
I assume this is some dumb thing, but any help appreciated.
After inspecting I think I found the culprit. Try edit your CSS like this:
li:hover ul {
display: block;
position: relative; /* relative, not absolute */
top: 100%;
left: -10px;
background-color: rgba(50, 50, 0, 1);
font-size: 13px;
}
Your problem is not entirely CSS. I just figured out that the LI's height is covering the dropdown. However, if you reduce the height of the LI, the next LI doesn't open the amount it needs to. A quick patch would be to apply this CSS below however, I would much rather get the JQuery guys here to help you out.
.accordian ul ul {
padding: 5px 12px;
display: none;
margin-top: 0px;
z-index: 99999;
position: relative;
background: none;
}
p.s. This solves the problem you asked, but you need to tweak the font and size so that there is no difference

how to display sub menus when hover

I have a vertical menu like this :
<ul>
<li>Level 1 menu
<ul>
<li>Level 2 item</li>
<li>Level 2 item</li>
</ul>
</li>
<li>Level 1 menu
<ul>
<li>Level 2 item</li>
<li>Level 2 item</li>
</ul>
</li>
<li>Level 1 menu</li>
</ul>
Now i need to display the Level 2 items once i hover so i added this line
#bar ul li:hover ul { display: block; }
in css but it didn't make any difference, and i have no other display tag in my css
#bar ul { list-style: none; margin: 0px; padding: 0px; }
#bar ul li { padding: 4px 0px 4px 0px; }
#bar ul li a { color: #FFF; font-size: 16px; }
#bar ul li a:hover { font-weight:bold }
#bar ul li ul li { padding: 4px 0px 4px 0px; margin-left:10px;}
#bar ul li ul li a { padding-left: 0px; font-size: 10px; }
As I understand right, you need to add #bar ul li ul { display: none; }
Here is example
#bar ul li ul { display: none;}
#bar ul li:hover ul { display: block; }
and also wrap your lists in element with id #bar
here is the demo
You should try using child selectors > (which are faster) with descendant ones wisely used. But a 5 level descendant selector is overkill.
Basically, first use a single descendant selector to affect all of them, and then a child one to override and set styles for the first level.
Something like this:
#menu { list-style: none; margin: 0px; padding: 0px; }
#menu li { padding: 4px 0px 4px 0px; margin-left:10px; }
#menu > li { padding: 4px 0px 4px 0px; margin-left:0; }
#menu a { color: #FFF; padding-left: 0px; font-size: 10px; }
#menu > li > a { font-size: 16px; }
#menu a:hover { font-weight:bold }
#menu ul { display: none; }
#menu li:hover > ul { display: block; }
Demo

Website Menu Bar Drop Down

I am working on a website for a client. For the menu/navigation bar, I created one for them (they were very specific) with dropdowns, but there is one problem--when you mouse over one of the items on the dropdown, it dissappears--check it out here http://www.brandonsdesigngroup.com/menu-expamle.html.
for the code, I call jquery from google API's, then there is the javascript, the CSS, and the actual content (in an unordered list).
Javascript:
<script type="text/javascript">
$(document).ready(function(){
$("#nav-one li").hover(
function(){ $("ul", this).fadeIn("fast"); },
function() { }
);
if (document.all) {
$("#nav-one li").hoverClass ("sfHover");
}
});
$.fn.hoverClass = function(c) {
return this.each(function(){
$(this).hover(
function() { $(this).addClass(c); },
function() { $(this).removeClass(c); }
);
});
};
</script>
CSS:
<style type="text/css">
.nav, .nav ul {
list-style: none;
margin: 0;
padding: 0;
height:20px
}
.nav {
z-index: 100;
position: relative;
}
.nav li {
border-left: 0px solid #000;
float: left;
margin: 0;
padding: 0;
position: relative;
font-family: Arial, Helvetica, sans-serif;
font-style:normal;
font-size:12px;
}
.nav li a, .nav li a:link, .nav li a:active, .nav li a:visited {
font:1.22em/25px "Arial Narrow", Arial, sans-serif letter-spacing:5px;
color: #FFFFFF;
display: block;
padding: 0 10px;
text-decoration: none;
text-style: narrow;
margin-right:26px;
}
.nav li a:hover {
margin-right:26px;
color: #FFFFFF;
}
#nav-one li:hover a,
#nav-one li.sfHover a {
color: #FFFFFF;
}
#nav-one li:hover ul a,
#nav-one li.sfHover ul a {
color: #FFFFFF;
height:20px;
background-image: url(menubar/transparent.png);
}
#nav-one li:hover ul a:hover,
#nav-one li.sfHover ul a:hover {
color:#FFFFFF;
background-image:url(menubar/transparent.png);
}
.nav ul {
border-bottom: 0px solid #FFFFFF;
list-style: none;
margin: 0;
width: 100px;
position: absolute;
top: -99999px;
left: 0px;
}
.nav li:hover ul,
.nav li.sfHover ul {
top: 22px;
}
.nav ul li {
border: 0;
float: none;
font-family: Arial, Helvetica, sans-serif;
font-style:normal;
font-size:10px;
}
.nav ul a {
border: 0px solid #000;
border-bottom: 0;
padding-right: 50px;
margin-bottom: 0px;
width: 130px;
white-space: nowrap;
}
.nav ul a:hover {
color: #FFFFFF;
}
</style>
<style type="text/css">
body {
width: auto;
height: auto;
background-color: #3A2C21;
}
</style>
HTML:
<td background="images/menu_bg.gif" height="25"><ul id="nav-one" class="nav">
<li>
HOME
</li>
<li>
PROFILE
<ul>
<li>ABOUT</li>
<li>PEOPLE</li>
<li>SERVICES</li>
<li>TRADE SHOWS</li>
</ul>
</li>
<li>
PORTFOLIO
<ul>
<li>ARTISTIC TILE</li>
<li>ATLANTIS</li>
<li>BLANCO</li>
<li>BUTLER"S OF FAR HILLS</li>
<li>HAMPTON FORGE</li>
<li>HILAND H. TURNER</li>
<li>MIELE</li>
<li>POGGENPOHL</li>
<li>THG FAUCETS</li>
<li>TOP KNOBS</li>
<li>VIXEN HILL</li>
</ul>
</li>
<li>
PUBLIC RELATIONS
<ul>
<li>PRESS ATTENTION</li>
<li>FRANK PR</li>
<li>HITS</li>
<li>MORE HITS</li>
<li>LEVERAGING PR</li>
</ul>
</li>
<li>
CONTACT
</li>
</ul>
Problem #1: Menu disappears before cursor can reach submenu.
Usually this is due to a gap between the <li> tag and the subnavigation <ul>. A gap of even one pixel will cause the navigation to disappear before the cursor can reach the submenu.
For instance, add a padding: 0 0 10px; to .nav li in your CSS, and the problem goes away.
You could also set a specific height for the <li> to cover the problem, too.
Problem #2: Menu disappears when cursor runs over the image slideshow.
As to the problem of your menu disappearing when you reach the point where your image slideshow and menu collide, that's due to a z-index problem.
You should set the .nav to have a z-index: 200 (or anything greater than 100, according to your slideshow -- I try to go overboard). This will make sure it sits above the gallery.
Javascript
<script>
sfHover = function() {
var sfEls = document.getElementById("navbar").getElementsByTagName("li");
for (var i=0; i<sfEls.length; i++) {
sfEls[i].onmouseover=function() {
this.className+=" hover";
}
sfEls[i].onmouseout=function() {
this.className=this.className.replace(new RegExp(" hover\\b"), "");
}
}
}
if (window.attachEvent) window.attachEvent("onload", sfHover);
</script>
html
Already a Member? Login
Become a Member?
Signup
Army
Navy
Airforce
I would use the Hover Intent plug-in. It is designed for exactly this kind of usage and helps provide a more robust dropdown.

Categories

Resources