Problem description:
In my menu when .mouseenter() the menu opens and when .mouseleave() it closes, but if i click a lot , the .mouseleave() event is executed.
This only happened on chrome browser.
I have other .click() events inside my menu, but every click I made, the .mouseleave() event is execute.
$(document).ready(function() {
$("#nav1 li").hover(
function() {
$(this).find('ul').slideDown();
},
function() {
$(this).find('ul').slideUp();
});
});
#nav1 a {
color: #FFFFFF;
}
#nav1 li ul li a:hover {
background-color: #394963;
}
div ul li ul {
background-color: #4a5b78;
list-style: none
}
#nav1 > li > a {
padding: 16px 18px;
display: block;
border-bottom: 2px solid #212121;
}
#nav1 li ul li a {
padding: 10px 0;
}
div {
background-color: #000000;
background-color: #343434;
width: 280px;
}
/* Hide Dropdowns by Default */
#nav1 li ul {
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="container">
<ul id="nav1">
<li>Hover here and infinite click
<ul>
<li>Stage1</li>
<li>Stage2</li>
<li>Stage3</li>
<li>Stage4</li>
</ul>
</li>
<li>Menu Heading 2
<ul>
<li>Stage1</li>
<li>Stage2</li>
<li>Stage3</li>
<li>Stage4</li>
</ul>
</li>
</ul>
<div>
Try click "Hover here and infinite click" to see this problem.
EDIT:
As you guys said, the problem occurs in this example.
Here is a video: Video link
When you click many times the browser has lost the element reference, try this example:
<div id="container">
<ul id="nav1">
<li>Menu Heading 1
<ul>
<li>Stage1</li>
<li>Stage2</li>
<li>Stage3</li>
<li>Stage4</li>
</ul>
</li>
<li>Menu Heading 2
<ul>
<li>Stage1</li>
<li>Stage2</li>
<li>Stage3</li>
<li>Stage4</li>
</ul>
</li>
<li>Menu Heading 3
<ul>
<li>Stage1</li>
<li>Stage2</li>
<li>Stage3</li>
<li>Stage4</li>
</ul>
</li>
</ul>
<div>
Css
ul,
li,
a {
padding: 0px;
margin: 0px;
}
.show {
display: block !important;
}
#nav1 a {
color: #FFFFFF;
}
#nav1 li ul li a:hover {
background-color: #394963;
}
div ul li ul {
background-color: #4a5b78;
list-style: none
}
#nav1 > li > a {
background-color: #343434;
padding: 16px 18px;
text-decoration: none;
display: block;
border-bottom: 2px solid #212121;
background: linear-gradient(top, #343434, #111111);
}
#nav1 li ul li a {
padding: 10px 0;
padding-left: 30px;
text-decoration: none;
display: block;
}
div {
background-color: #000000;
background-color: #343434;
width: 280px;
}
/* Hide Dropdowns by Default */
#nav1 li ul {
display: none;
}
JS
$(document).ready(function() {
$("#nav1 li").hover(
function(e) {
let ulMenu = $(this).find('ul');
ulMenu.addClass('show');
//$(this).find('ul').slideDown();
},
function(e) {
if(e.relatedTarget){
let ulMenu = $(this).find('ul');
ulMenu.removeClass('show');
} else {
console.log('fail ');
}
//$(this).find('ul').slideUp();
});
});
Codepen Example Works
You can add a stropPropagation in your click event.
$("#nav1 li").click(
function(e){
e.stopPropagation();
});
maybe the event is getting lost in the process, try to verify it, and if so set the actual element.
see this: https://api.jquery.com/event.relatedTarget/
Related
I created a simple navigation, but it doesn't work on mobile. When you click on the plus symbol or "Book 1 name" the list of links are suppose to appear, but for some reason it doesn't work, and when you click the plus symbol the ex symbol is suppose to appear. The book title should link should work on desktop, but not on mobile. Thanks!
$(document).ready(function () {
$(window).resize(function() {
if($(window).width() <= 550) {
$('.bookName').click(function(e){
e.preventDefault();
$('.bookNavigation ul li ul').toggleClass('toggleNav')
$(this).toggleClass('changeIcon');
});
} else {
$('.bookName').click(function(e){
return true;
});
}
});
});
.bookNavigation ul li ul{
display: flex;
}
.toggleNav{
display: block;
}
#media only screen and (max-width: 550px) {
.bookNavigation ul li ul{
display: none;
}
.bookName::before{
content: '+';
padding-right: 10px;
}
.bookName .changeIcon::before{
content: '-';
padding-right: 10px;
}
}
a{
text-decoration: none;
}
li{
list-style: none;
}
.bookNavigation{
margin-bottom: 100px;
}
.bookName{
text-transform: uppercase;
font-size: 30px;
}
li{
margin-right: 30px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<nav class="bookNavigation">
<ul>
<li>
Book 1 Name
<ul>
<li>Book 1 Chapter 1</li>
<li>Book 1 Chapter 2</li>
<li>Book 1 Chapter 3</li>
</ul>
</li>
</ul>
</nav>
<p>you are in Book 1 Name cover page</p>
You can do this check $(window).width() <= 550 inside the click event rather than attaching the event based on screen-size. Please find the corrected code.
$('.bookName').click(function(e) {
if ($(window).width() <= 550) {
e.preventDefault();
$('.bookNavigation ul li ul').toggleClass('toggleNav')
$(this).toggleClass('changeIcon');
}
});
.bookNavigation ul li ul {
display: flex;
}
.bookNavigation ul li ul.toggleNav {
display: block;
}
#media only screen and (max-width: 550px) {
.bookNavigation ul li ul {
display: none;
}
.bookName::before {
content: '+';
padding-right: 10px;
}
.bookName .changeIcon::before {
content: '-';
padding-right: 10px;
}
}
a {
text-decoration: none;
}
li {
list-style: none;
}
.bookNavigation {
margin-bottom: 100px;
}
.bookName {
text-transform: uppercase;
font-size: 30px;
}
li {
margin-right: 30px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<nav class="bookNavigation">
<ul>
<li>
Book 1 Name
<ul>
<li>Book 1 Chapter 1</li>
<li>Book 1 Chapter 2</li>
<li>Book 1 Chapter 3</li>
</ul>
</li>
</ul>
</nav>
<p>you are in Book 1 Name cover page</p>
Instead of checking on resize, check the window with inside buttonClickHandler like below
$(button).on('click', function(){
if($(window).width() <= 550){
// Code to toggle list
}
});
Another problem was the specificity of toggleNav css class.
.bookNavigation ul li ul {
display: none;
}
Above code is more specific than
.toggleNav {
display: block;
}
So the toggling toggleNav won't work because the 1st one will override this one. For fixing it create a class like the one below and toggle it on click. So that it will be hidden initially and will be removed on click.
.navHidden {
display: none
}
Check this pin for working example: https://codesandbox.io/s/bold-currying-39w11
So I'm trying to create an accordion style menu where if you click a panel it opens the section. If you click it again, it closes. On top of that, it should also close any other panel that was previously opened.
I've almost got that functionality but the problem is that I have to click it twice.
To see what I mean, check out this Fiddle
You'll notice that if you open link one then try to open link 2, you'll have to press link 2 twice.
How can I make it so that you only have to press it once to close link 1 but also open link 2 ?
let dropdown = document.querySelectorAll('.dropdown-toggle');
const handleClick = (e) => {
const active = document.querySelector('.open');
if(active){
active.classList.remove('open');
} else {
e.currentTarget.nextElementSibling.classList.add('open')
}
}
dropdown.forEach(element => {
element.addEventListener('click', handleClick);
});
body {
background: #ccc;
}
.menu {
background: #fff;
margin: 0 auto;
max-width: 400px;
}
.menu ul {
padding: 0;
text-align: center;
width: 100%;
}
.menu ul li {
list-style: none;
padding: 20px 0;
border-bottom: 1px solid #ccc;
}
.menu ul li a {
text-decoration: none;
}
.menu ul li .dropdown {
display: none;
padding: 20px;
background: grey;
}
.menu ul li .dropdown.open {
display: block;
}
<div class="menu">
<ul>
<li>
link 1
<div class="dropdown">Some text</div>
</li>
<li>
link 2
<div class="dropdown">Some text</div>
</li>
<li>
link 3
<div class="dropdown">Some text</div>
</li>
<li>
link 4
<div class="dropdown">Some text</div>
</li>
<li>
link 5
<div class="dropdown">Some text</div>
</li>
</ul>
</div>
Can use js like the following.
let dropdown = document.querySelectorAll('.dropdown-toggle');
const handleClick = (e) => {
const isLastOpenTargetClicked = e.currentTarget.nextElementSibling.classList.contains('open');
if(isLastOpenTargetClicked) {
e.currentTarget.nextElementSibling.classList.remove('open');
return;
}
const active = document.querySelector('.open');
if(active){
active.classList.remove('open');
}
e.currentTarget.nextElementSibling.classList.add('open')
}
dropdown.forEach(element => {
element.addEventListener('click', handleClick);
});
body {
background: #ccc;
}
.menu {
background: #fff;
margin: 0 auto;
max-width: 400px;
}
.menu ul {
padding: 0;
text-align: center;
width: 100%;
}
.menu ul li {
list-style: none;
padding: 20px 0;
border-bottom: 1px solid #ccc;
}
.menu ul li a {
text-decoration: none;
}
.menu ul li .dropdown {
display: none;
padding: 20px;
background: grey;
}
.menu ul li .dropdown.open {
display: block;
}
<div class="menu">
<ul>
<li>
link 1
<div class="dropdown">Some text</div>
</li>
<li>
link 2
<div class="dropdown">Some text</div>
</li>
<li>
link 3
<div class="dropdown">Some text</div>
</li>
<li>
link 4
<div class="dropdown">Some text</div>
</li>
<li>
link 5
<div class="dropdown">Some text</div>
</li>
</ul>
</div>
There's no need to check whether the current element is active; On the click handler you simply want to check whether the .nextElementSibling's .classList contains the class open. If it does, remove it. If it doesn't, apply it.
This can be seen in the following:
let dropdown = document.querySelectorAll('.dropdown-toggle');
const handleClick = (e) => {
if (e.currentTarget.nextElementSibling.classList.contains('open')) {
e.currentTarget.nextElementSibling.classList.remove('open');
} else {
e.currentTarget.nextElementSibling.classList.add('open')
}
}
dropdown.forEach(element => {
element.addEventListener('click', handleClick);
});
body {
background: #ccc;
}
.menu {
background: #fff;
margin: 0 auto;
max-width: 400px;
}
.menu ul {
padding: 0;
text-align: center;
width: 100%;
}
.menu ul li {
list-style: none;
padding: 20px 0;
border-bottom: 1px solid #ccc;
}
.menu ul li a {
text-decoration: none;
}
.menu ul li .dropdown {
display: none;
padding: 20px;
background: grey;
}
.menu ul li .dropdown.open {
display: block;
}
<div class="menu">
<ul>
<li>
link 1
<div class="dropdown">Some text</div>
</li>
<li>
link 2
<div class="dropdown">Some text</div>
</li>
<li>
link 3
<div class="dropdown">Some text</div>
</li>
<li>
link 4
<div class="dropdown">Some text</div>
</li>
<li>
link 5
<div class="dropdown">Some text</div>
</li>
</ul>
</div>
Inside your click handler, loop the document.querySelectorAll('.dropdown-toggle'), remove all the open from classlist, then add open to the current target
Alright so I'm using jQueryMobile, jQuery/JavaScript and CSS to make a navigation bar that allows you to select an option from the top UL tree (horizontal nav bar) and then also select an option from the resulting submenu while the option from the parent ul tree is still highlighted.
This works in a desktop browser and in this jsfiddle I just created (at the bottom); however, once I'm in a mobile browser (Android Internet or Chrome Mobile), the parent ul no longer stays highlighted.
Why?
<div data-role="page" data-theme="a" id="home">
<div data-role="header" data-position="fixed">
<nav id="navbar" data-role="navbar">
<ul>
<li class="active"><a class="ui-btn-active" href="#">Real-Time</a>
<ul class="secondLvl">
<li>Choice 1</li>
<li>Choice 2</li>
<li>Choice 3</li>
<li class="lastNav"><a></a></li>
</ul>
</li>
<li>Database Functions
<ul class="secondLvl">
<li>Another Choice 1</li>
<li>Another Choice 2</li>
<li class="lastNav"><a></a></li>
</ul>
</li>
<li>Settings/Configuration
<ul class="secondLvl">
<li>Logout</li>
<li>A Third Choice 1</li>
<li>A Third Choice 2</li>
<li>A Third Choice 3</li>
<li class="lastNav"><a></a></li>
</ul>
</li>
</ul>
</nav>
</div>
<div data-role="main" class="ui-content">
</div>
<div data-role="footer" data-position="fixed">
<h1>
Home
</h1>
</div>
</div>
CSS:
#home
{
background-color: #5f6975;
overflow: hidden;
}
#navbar > ul {
position: relative;
}
#navbar ul ul {
display: none;
background: #5f6975;
border-radius: 0px;
padding: 0;
position: absolute;
top: 100%;
left: 0;
width: auto;
bottom: 1000px;
}
#navbar ul ul li {
float: left;
border-top: 1px solid #6b727c;
border-bottom: 1px solid #575f6a;
position: relative;
width: 100%;
}
.ui-navbar li:last-child .ui-btn {
margin-right: 0px !important;
}
.lastNav a {
height: 100vh;
pointer-events: none;
}
#navbar ul ul li a.active {
background: #4b545f;
}
#navbar ul ul ul {
position: absolute;
left: 100%;
top: 0;
}
#navbar ul li.active > ul {
display: block;
}
#navbar ul li {
float: left;
}
#navbar ul li.active {
background: #4b545f;
background: linear-gradient(top, #4f5964 0%, #5f6975 40%);
background: -moz-linear-gradient(top, #4f5964 0%, #5f6975 40%);
background: -webkit-linear-gradient(top, #4f5964 0%,#5f6975 40%);
}
#navbar ul li a {
display:block;
padding: 25px 40px;
text-decoration: none;
}
JavaScript/JQuery:
//Clear Text Fields
$(document).on("pagehide", function (e){
$(e.target).remove();
});
//Setup Side Navbar
$(document).on("pagecreate", "#home", function(){
var navItems = $("#navbar > ul > li");
var subWidth = 100 / navItems.length;
$("#navbar > ul > li").each(function( index ) {
$(this).find("ul").each(function(i) {
var top = (i + 1) * 100;
$(this).css({"position": "absolute",
"width": subWidth + "%",
"top": top + "%"});
});
});
});
//Make Side Navbar stick
$(document).on('pagebeforeshow','#home', function(event){
$('#navbar ul li').on('click', function () {
//removing the previous selected menu state
$('#navbar ul li.active').removeClass('active');
//is this element from the second level menu?
if($(this).closest('ul').hasClass('secondLvl'))
{
$(this).parents('li').addClass('active');
} //end if
//otherwise just highlight the element
else
{
$(this).addClass('active');
} //end else
})
$('ul').find('a').on('click', function() {
$(this).closest('ul').find('a').removeClass('ui-btn-active');
if($(this).closest('ul').hasClass('secondLvl'))
{
$(this).addClass('ui-btn-active');
}
})
})
Here's my JSFiddle: https://jsfiddle.net/LLx7vgjo/8/
Try using vclick event instead click. The jQuery Mobile "vclick" event handler simulates the "onclick" event handler on mobile devices. I hope this helps!
Is there a way through JavaScript to set the links on a timer before its closes out? I don't want it to seem so sensitive. Such as if a user accidentally mouses off the link it closes right away. Any video recommendation or links?
Thanks,
I am not using jQuery......
* {
padding: 0;
margin: 0;
}
body {
padding: 5px;
font-family: Cambria, "Hoefler Text", "Liberation Serif", Times, "Times New Roman", serif;
}
ul {
list-style: none;
}
ul li {
float: left;
padding-right: 1px;
position: relative;
}
ul a {
display: table-cell;
vertical-align: middle;
width: 100px;
height: 50px;
text-align: center;
background-color: #2F2F2F;
color: #AE0002;
text-decoration: none;
}
ul a:hover {
background-color: #828282;
color: #FFFFFF;
}
li > ul {
display: none;
position: absolute;
left: 0;
top: 100%;
}
li:hover > ul {
display: block;
}
li > ul li {
padding: 0px;
padding-top: 1px;
}
li > ul li > ul {
left: 100%;
top: 0;
padding-left: 1px;
}
li > ul li > ul li {
width: 100px;
}
<body>
<ul>
<li>Sports News
<ul>
<li>Football
<ul>
<li>NFL
</li>
<li>ESPN Football
</li>
</ul>
</li>
<li>Baseball
<ul>
<li>MLB
</li>
<li>ESPN Baseball
</li>
</ul>
</li>
<li>Soccer
<ul>
<li>FIFA
</li>
<li>ESPN Soccer
</li>
</ul>
</li>
<li>Basketball
<ul>
<li>NBA
</li>
<li>ESPN Basketball
</li>
</ul>
</li>
<li>Auto Racing
<ul>
<li>ESPN Racing
</li>
<li>Nascar
</li>
</ul>
</li>
</ul>
</li>
</ul>
</body>
Instead of css, show/hide ul using javascript. Handle mouseover and mouseout events to show/hide. To delay, on hover, show using timer and on mouseout, hide as well as clear the timer.
function show(ul) {
ul.css("display", "inline-block");
}
function hide(ul) {
ul.css("display", "none");
}
$("li").mouseover(function () {
var ul = $(this).children("ul");
var timer = setTimeout(function () {
show(ul);
}, 400);
$(this).data("timer", timer);
}).mouseout(function () {
var ul = $(this).children("ul");
var timer = $(this).data("timer");
clearTimeout(timer);
hide(ul);
});
Demo: http://jsfiddle.net/k06dLnmk/
You can use transition delay.
transition-delay:1s;
Similar Question:
Delay hover
or you can use javascript to toggle with the css clasess
window.setInterval("javascript function", milliseconds);
Edit: Oh sorry as the comment pointed out. display none does not work with transition delay. Would you consider using visibility property instead?
div > ul {
. . .
visibility:hidden;
opacity:0;
transition:visibility 0s linear 0.5s,opacity 0.5s linear;
}
div:hover > ul {
visibility:visible;
opacity:1;
transition-delay:0s;
}
I'm looking to have an additional subnav to this accordion menu. I tried to add a child element to the nav ul li, but that didn't seem to work. Ideally, I would like to be able to list web projects under "web" and print under "print".
FIDDLE: http://jsfiddle.net/schermerb/rGMAu/1/
.header button {
cursor:pointer;
float:right;
padding:5px;
margin:10px 10px;
border:none;
border:1px solid #ececec;
background:#444;
color:#ececec;
}
.nav {
text-align:center;
background:#444;
}
.nav ul li {
text-transform:capitalize;
display:block;
border-bottom:1px solid #ececec;
}
.nav a {
display:block;
padding:10px;
color:#ececec;
}
.nav a:hover {
background:#029b9d;
color:#ececec;
}
<button id="show">Menu <span>+</span> <span style="display:none;">-</span>
</button>
<div class="clear"></div>
</div>
<div class="nav">
<ul>
<li>Home
</li>
<li>About
</li>
<li>Web
</li>
<li>Print
</li>
</ul>
</div>
I have updated your js
$('.nav, .nav li ul').hide();
$('#show').click(function () {
$(".nav").toggle();
$("span").toggle();
});
$('.nav li').click(function(){
$(this).children('ul').toggle();
});
Updated jsFiddle File
Adding a child element was the right path.
http://jsfiddle.net/jonigiuro/rGMAu/2/
<li>Web
<ul class="sub">
<li class="item">item1</li>
<li class="item">item2</li>
</ul>
</li>
You hide the child element by default, and when you hover on the parent, you show the it:
ul li:hover ul
Here's the revelant css for your case:
.nav ul li ul {
color: red;
margin: 0;
padding: 0;
display: none;
}
.nav ul li:hover ul {
display: block;
}
.nav ul li ul li {
padding: 10px 0;
}