Dropdown Menu: Infinite Slide on Hover with jQuery - javascript

I have created a simple dropdown menu with jquery
https://jsfiddle.net/pmksgz3w/
HTML
<ul>
<li>Page A</li>
<li>Page B
<ul>
<li>Dropdown</li>
<li>Dropdown</li>
</ul>
</li>
</ul>
Jquery
$(document).ready(function(){
$('ul> li').hover(function() {
$(this).find('ul').slideToggle();
});
});
When I hover over Page B, then the dropdown menu is shown. If I move the curser from Page B very slowly to the right (see picture) then the drop-down menu will close, since the li is not hovered for a short moment. How can I prevent that the dropdown menu will instantly close?
An even worse problem happens if I move the cursor extremely fast to the dropdown menu. Because then, the dropdown menu will slideUp and slideDown in an infinite loop.
I found at How to tell .hover() to wait? a promising solution from 2009 but the answer does not work when I try it,(Edit note: It works now, see edit below). Further it is mentioned that one should use hoverIntend plugin. I downloaded the plugin and changed my jQuery code to
$(document).ready(function(){
$('ul> li').hoverIntend(function() {
$(this).find('ul').slideToggle();
});
});
and although it improves some things, the above problem that it instantly closes and the infinite loop remains. How can I solve this problem?
Edit: I managed to solve the first problem! Now the dropdown does not close instantly!
https://jsfiddle.net/5sxvsu8w/
I had to change the jQUery code as follows:
$(document).ready(function(){
var timer;
$('ul> li').hover(function() {
clearTimeout(timer);
$(this).find('ul').slideDown('fast');
}, function() {
var list = $(this).find('ul');
timer= setTimeout(function() {
list.slideUp('fast');
}, 2000);
});
});
However, the infinite loop problem remains.

The solution you found in here is usefull, this javascript code maybe can help:
$(document).ready(function(){
$('.menu li').hover(
function () {
$('.sub', this).stop().slideDown(650);
},
function () {
$('.sub', this).stop().slideUp(650);
}
);
});
/*$('ul >li').hover(function() {
clearTimeout($(this).data('timeout'));
$('li > ul').slideDown('fast');
}, function() {
var t = setTimeout(function() {
$('li > ul').slideUp('fast');
}, 650);
$(this).data('timeout', t);
});*/
li{
list-style-type:none;
display: inline-block;
position: relative;
padding: 20px;
background-color: #08c;
}
li ul li{
min-width:200px;
}
li ul{
margin:0;
padding:0;
position: absolute;
top: 100%;
left:0;
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<ul class="menu">
<li>Page A</li>
<li>Page B
<ul class="sub">
<li>Dropdown</li>
<li>Dropdown</li>
</ul>
</li>
</ul>
EDIT: I have changed my javascript code after some reseach; this solution unfortunately does not solve completely the first problem (it is still based on a timer) but avoids the infinite loop.

Related

Smooth toggle in jQuery

I am using some simple jQuery to animate a toggle button. The toggle works, however, no matter how I try changing values, I cannot seem to change the speed or smoothness of the animation.
I have looked at different methods and tried changing the values within the .sliderUp section, it just isn't working for me.
The code I am using is:
$(document).ready(function(){
$("a.toggle").click(function(){
if ($("nav ul").hasClass("expanded")) {
$("nav ul.expanded").removeClass("expanded").slideUp(250);
$(this).removeClass("open");
} else {
$("nav ul").addClass("expanded").slideDown(250);
$(this).addClass("open");
}
});
});
-
<nav>
Toggle Menu
<ul>
<li>Menu Item</li>
<li>Menu Item</li>
</ul>
</nav>
-
nav {
width: 100%;
ul {
display: none;
width: 100%;
&.expanded {
display: block;
}
}
.toggle {
display: block !important;
}
}
Try to use slideToggle
Syntax
$(selector).slideToggle(speed,callback);
Here the optional speed parameter can take the following values: "slow", "fast", milliseconds.
So i think you need to put more time to get smooth animation.
Jquery
$(document).ready(function(){
$("a.toggle").click(function(){
$("nav ul").slideToggle(1500);
$(this).toggleClass("open");
});
});
Here is the working jsfiddle:https://jsfiddle.net/88bm4x6z/1/
If any of you still not been able to slide smoothly, just set transition: none;. if you'r using it in your parent item or child, I stuck in it for 3 hours. Then I just set it to none, it worked.

To know if mouse still hover menu

I have the following menu construction very resumed (cant change HTML code due is impossible, only CSS and JS!):
$('span').on("hover", handleHover('span'));
function handleHover(e) {
$(e).on({
mouseenter: function() {
$(this).addClass('selecc');
$(this).next("ul").show();
},
mouseleave: function() {
$(this).removeClass('selecc');
$(this).next("ul").hide();
}
});
}
span {
display:block;
}
ul {
background-color:#CCC;
color:#000;
display:none;
margin:0;
}
.selecc {
background-color:Red;
color:#FFF
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<span>Option 1</span>
<ul>
<li>suboption 1-1</li>
<li>suboption 1-2</li>
<li>suboption 1-3</li>
</ul>
<span>Option 2</span>
<ul>
<li>suboption 2-1</li>
<li>suboption 2-2</li>
<li>suboption 2-3</li>
</ul>
I need to move the mouse over the suboptions but the menu closes and i dont know how to tell to jquery that UL is part of menu group. Some idea for this?
No-one said you cannot alter the HTML dynamically using jQuery :)
So, yes, group your SPAN+UL into groups, and attach the hover function to your .group wrapper:
jsBin demo
$("span").each(function(){
var ul = $(this).next("ul");
$(this).add(ul).wrapAll("<div class='group'/>");
});
$(".group").hover(handleHover);
function handleHover() {
$("span",this).toggleClass('selecc');
$("ul",this).stop().slideToggle();
}

Problems creating sidebar toggle dropdown menu

I'm working on http://www.variied.com/market/men/. I'm trying to create a toggle dropdown menu on the sidebar that is triggered when someone hits the "Tops" link on the sidebar, which will then toggle the content in the sub-menu to be displayed. Here's my current code
<style>
ul.category ul.sub-menu ul.sub-menu li a{
display:none
}
</style>
<script>
jQuery(document).ready(function() {
jQuery("#menu-item-746").click(function() {
jQuery(this).next("ul.category ul.sub-menu ul.sub-menu li a").toggle();
return false;
});
});
</script>
There are a few issues in this fiddle:
You have a class called #submenu it should just be submenu
You're passing the event so you can use e.preventDefault() (unless you prefer return false)
I would suggest setting the subnav ul to display: none and just toggling that and I would use slideToggle for a nicer effect.
JS
$("#menu-item-746").click(function(e) {
e.preventDefault();
$(this).next("ul").slideToggle();
});
HTML
<ul class="submenu">
<li id="menu-item-746">Test Item</li>
<ul>
<li>Test1</li>
<li>Test2</li>
</ul>
</ul>
CSS
.submenu ul{
display: none;
}
FIDDLE
UPDATE
I looked at your HTML on your site and it appears that your ul subnav is a child of your li not a sibling (it was a sibling in your fiddle). Try this:
$(this).find("ul").slideToggle();
Also from the code you have provided you are targeting an id which means this would only work for that 1 element. It appears the ones with a subnav have a class called .menu-item-has-children so I would target that, like so:
$(".sub-menu .menu-item-has-children").click(function(e) {
e.preventDefault();
$(this).find("ul.sub-menu").slideToggle();
});
NEW UPDATE
Target the a instead then:
$(".sub-menu .menu-item-has-children").on("click", " a:first", function(e) {
e.preventDefault();
$(this).siblings("ul.sub-menu").slideToggle();
});

jQuery navigation-items with nested submenus should open on click

I need to add a second level of submenus here.
Is there a dynamic solution, so only one submenu is opened, when clicking on the link?
And when clicking a link to a submenu (in the first submenu), then open this one?
And so on…
I already changed the jsfiddle a little, to have one level of sublevels more: http://jsfiddle.net/cRsZE/363/
Working example with one level of submenus: JSFiddle Demo
HTML:
<ul id="nav">
<li>Home</li>
<li class="parent">About
<ul class="sub-nav">
<li>Johnny</li>
<li>Julie</li>
<li>Jamie</li>
</ul>
</li>
<li>Contact</li>
</ul>
CSS:
#nav ul.sub-nav {
display: none;
}
#nav ul.visible {
display: block;
}
jQuery:
$(document).ready(function() {
$('.parent').click(function() {
$('.sub-nav').toggleClass('visible');
});
});
Source: Creating Drop Down Menu on click CSS
Try,
CSS:
.hidden {
display: none;
}
JS:
$('ul ul').addClass('hidden');
$(document).ready(function () {
$('.parent').click(function (e) {
e.stopPropagation();
$(this).find('ul').first().toggleClass('hidden');
});
});
DEMO

iOS click is activating parent anchor of dropdown menu

Iv run out of solutions that I can think of or find for this problem. I'm working on a fixed to the top of the page. The left side has a anchor that takes you to the top of the page, if hovered over it will show other external links. The right side is a list of page sections with anchors to scroll you to them.
this all works fine on desktop as hover and click are separate events, but on an ipad they are they same. On an iPad you should be able to touch the "Product List" list item and have the drop down menu appear. If touched again it will take you back to the top. Right now when you touch it will take you back to the top and display the hover.
Here is a jsfiddle recreating the code and issue. http://jsfiddle.net/hyaTV/5/
HTML
<ul class="one">
<li><a class="intrapage" href="#stage">Product Title</a>
<ul>
<li>other product</li> <!-- link that goes to different page -->
<li>other product</li> <!-- link that goes to different page -->
</ul>
</li>
</ul>
<ul class="two">
<li><a class="intrapage" href="#section_one">birds</a></li> <!-- goes to Birds section -->
<li><a class="intrapage" href="#section_two">bees</a></li> <!-- goes to bees section -->
</ul>
CSS
ul.one{float:left;list-style:none;}
ul.one ul{display:none;}
ul.one > li:hover ul{display:block;}
/* styling for right side nav */
ul.two{float:right;list-style:none;}
ul.two li{display:inline-block;}
JS
// scrolls window to element id with easing
$(".intrapage").click(function(event) {
event.preventDefault();
$('html,body').animate({scrollTop:$(this.hash).offset().top}, 850);
return false;
});
You could use iOS :hover issue to your advantage. I believe by changing your CSS to
ul.one > li ul { display: none; }
ul.one > li:hover ul { display: block; }
That said, above problem doesn't exist on other mobile OS. there're no way to mouse out on iOS.
It's better to detect if user is on mobile device and add .mobile with javascript to <body> then toggle the sub-menu on click events.
CSS
ul.one > li:hover ul, ul.one > li.hover ul { display: block; }
JS
$('body.mobile ul.one > li').click(function(e) {
$(this).toggleClass('hover');
});
I came up with a solution which appears to work. It will require your page to include the Modernizr JS to check if touch is supported or not.
JS
if (document.addEventListener) {
document.addEventListener("touchstart", function(){}, true);
}
if($('html').hasClass('touch')){
$('.one > li').click(function(e){
if($(this).hasClass('hover')){
// $(this).removeClass('hover');
} else {
$(this).toggleClass('hover');
}
});
$('html').bind('touchstart', function(){
if($('.one > li').is(':hover')){
// do nothing
} else {
$('.one > li.hover').removeClass('hover');
}
});
$('.one a.intrapage').click(function(event){
if($('.one > li').hasClass('hover')){
event.preventDefault();
$('html,body').animate({scrollTop:$(this.hash).offset().top}, 850);
return false;
} else {
event.preventDefault();
}
});
$(".two .intrapage").click(function(event) {
event.preventDefault();
$('html,body').animate({scrollTop:$(this.hash).offset().top}, 850);
return false;
});
} else {
$(".intrapage").click(function(event) {
event.preventDefault();
$('html,body').animate({scrollTop:$(this.hash).offset().top - 50}, 850);
return false;
});
}

Categories