jQuery: Delay showing of a dropdown menu content - javascript

I have built a dropdown menu that works fine. It goes like this:
Main menu items are in horizontal bar, then
When hover on any item, big dropdown box (with submenu links) is shown.
And here is my code for this:
HTML:
<!-- Based on Bootstrap -->
<div class="navbar navbar-inverse">
<div class="nav-collapse collapse">
<ul class="nav">
<li>First item
<div id="about-horizontal-submenu" class="horizontal-submenu">
<div class="submenu-container span3">
<ul>
<li>Links</li>
<li>Links</li>
</ul>
</div>
<!-- and 4x similar div (to have 12 cols) -->
</div>
</li>
<li>Dropdown
<div id="about-horizontal-submenu" class="horizontal-submenu">
<!-- 3x similar div (like above) and then: -->
<div class="submenu-container span3">
<ul>
<li>I want to go here</li>
<li>Links</li>
</ul>
</div>
</div>
</li>
<!-- And then goes another main menu item... -->
</ul>
</div>
</div>
</div>
JS:
jQuery(document).ready(function($) {
'use strict';
$('.navbar .nav > li').hover(function() {
var $el = $(this);
$el.addClass('hover');
var $submenu = $el.find('.horizontal-submenu');
if ($submenu.is(':hidden')) {
$submenu.slideDown(200);
}
}, function() {
var $el = $(this);
$el.removeClass('hover');
var $submenu = $el.find('.horizontal-submenu');
if ($submenu.is(':visible')) {
$submenu.hide();
}
});
});
Problem
I think I need to add a little delay before both - sliding Down submenu on very first hover and - changing submenu content (when switching/hovering to another menu item).
Why?
When you hover on "Dropdown" and want to choose "I want to move here":
You have to go down from "Dropdown" item and then to the right - which is ok (but not very usable).
Problem is, when you go like the image is showing (from the "Dropdown" straight to the "I want to move here" - you catch "Third item" on your way and immidiatelly see the content that belongs to "Third item". And that's not very good.
If you could show me how to delay/ignore hover on my menu items for very short time, I would be grateful. (I found great example behavior of menu on: http://FEI.com)

Ben Kamens from Khan Academy wrote an article regarding this exact problem, outlining how Amazon.com solved it. It is a great read!
http://bjk5.com/post/44698559168/breaking-down-amazons-mega-dropdown
He also put together a jQuery plugin to solve this problem with a working demo. You can find it on GitHub here:
https://github.com/kamens/jQuery-menu-aim
http://htmlpreview.github.io/?https://github.com/kamens/jQuery-menu-aim/blob/master/example/example.html

$(function($) {
var m;
var timer="";
var wait=200;
active=function(){
$('.navbar .nav > li').mouseover(function() {
m = $(this);
if(timer==""){
test();
unb();
timer = setTimeout(reb,wait);
}
});
}
test = function(){
$(".horizontal-submenu").stop().hide(300);
m.find(".horizontal-submenu").stop().show(300);
};
unb = function(){
$('.navbar .nav > li').unbind('mouseover');
};
reb = function(){
timer="";
active();
};
$(".horizontal-submenu").hide(300);
active();
});
Adjust 'wait' for your best timing; You can just copy and try on your script.

This might be what you are looking for:-
http://cherne.net/brian/resources/jquery.hoverIntent.html
From this you need 2 lines on your web page to activate the hover to working properly
1) Loading script hoverIntent
2) Change from hover to hoverIntent in your jQuery

please try setTimeout. It always does the trick.

Related

Slicknav autoclosing multilevel menus

I'm working with slicknav for my mobile menu. I came across a cool little way to have the Parent menu close automatically if you click on another Parent menu and I have it working perfectly if I'm using it like below (please note, i do not know javascript. What you see is me hacking some together from other code I've found online):
<ul id="menu">
<li class="first">Parent1
<ul>
<li>Child1</li>
<li>Child2</li>
</ul>
</li>
<li>Parent2
<ul>
<li>Child3</li>
<li>Child4</li>
</ul>
</li>
<li>Parent3
<ul>
<li>Child5</li>
<li>Child6</li>
</ul>
</li>
</ul>
javascript:
<script>
$(function(){
$('#menu').slicknav({
label: 'MENU',
duration: 150,
allowParentLinks: true,
'open': function(trigger){
var that = trigger.parent().children('ul');
$('.slicknav_menu ul li.slicknav_open ul').each(function(){
if($(this).get( 0 ) != that.get( 0 )){
$(this).slideUp().addClass('slicknav_hidden');
$(this).parent().removeClass('slicknav_open').addClass('slicknav_collapsed');
}
})
},
closeOnClick:true
});
});
$("#content").click(function(){
$('#menu').slicknav('close');
});
</script>
I'm needing to make some of the children items have their own dropdowns. Is there a way to make the javascript function with the same idea? If it is unchanged, when you tap/click on any of the children items with their own ul li items, it opens, then immediately closes.
if I remove this:
var that = trigger.parent().children('ul');
$('.slicknav_menu ul li.slicknav_open ul').each(function(){
if($(this).get( 0 ) != that.get( 0 )){
$(this).slideUp().addClass('slicknav_hidden');
$(this).parent().removeClass('slicknav_open').addClass('slicknav_collapsed');
}
})
then the autoclosing stops. Parent and children/parents remain open.
I'd like to be able to tap the children/parent and have it remain open unless you're tapping on another children/parent item. I'm sorry if i'm not making sense. Tired and this is about the best I can do....
As stated at the beginning of this post, javascript is not my language... Any ideas or pointers would be greatly appreciated.

Show divs with jQuery

I have this code http://jsfiddle.net/cwahL1tz/
My HTML
<ul class="myFilters">
<li data-type="A">A</li>
<li data-type="B">B</li>
<li data-type="C">C</li>
</ul>
<div class="filter">
<ul class="title">
<li>Assurance</li>
<li>Couverture</li>
<li>Banque</li>
<li>Alimentation</li>
</ul>
<div id="Assurance" class="category">
<ul>
<li>Groupama</li>
</ul>
</div>
<div id="Couverture" class="category">
<ul>
<li>Try it !</li>
</ul>
</div>
<div id="Alimentation" class="category">
<ul>
<li>AN example</li>
</ul>
</div>
</div>
Here's my JS script
jQuery(function ($) {
$('.myFilters li').click(function(){
$(".category").hide();
var v = $(this).text()[0]
$('.title li').hide().filter(function(){
return $(this).text().toUpperCase()[0] == v;
$(".category:first").show();
}).show()
})
$("a[data-toggle]").on("click", function(e) {
e.preventDefault(); // prevent navigating
var selector = $(this).data("toggle"); // get corresponding element
$(".category").hide();
$(selector).show();
});
});
It works fine but I trying to arrange some stuff but I'm stuck.
When I load the page all the links and divs appears, I just only want the divs of the first letter appear.
And when I click on C for example, I want the first div to show from the first link.
Thanks for your help !
EDITED:
On load:
$('.myFilters li:first').trigger('click');
And inside its click:
.first().find('a[data-toggle]:first').trigger('click');
jsfiddle DEMO
You can simply do that with first selecting the element with the right selector and then you can trigger the click event manually :
Show the Assurance content on load :
$('a[data-toggle="#Assurance"]').click();
Show first content on click :
$('.myFilters li').click(function(){
$(".category").hide();
var v = $(this).text()[0]
$('.title li').hide().filter(function(){
return $(this).text().toUpperCase()[0] == v;
}).show()
$('a[data-toggle]:visible:first').click();
})
Updated jsFiddle
Without going into any more javascript, you can display the content the way you would like using css selectors:
.category {display:none;}
.category:nth-of-type(1) {
display:block;
}
http://jsfiddle.net/5ageasm4/1/
Is this what you want. Check the Fiddle
I am basically just triggering the first item in the li
$(".title > li:first").find("a[data-toggle]").trigger("click");
and i am doing the same with the category.
EDIT
I updated my Fiddle
NEW EDIT
Created a new Fiddle, this one just removes all the duplicate code.
So basically i created these 2 functions
that.selectFirstElem = function(selector){
selector.find("a[data-toggle]").trigger("click");
};
that.loadFirstDataToggle = function(input){
return $('.title li').hide().filter(function(){
return $(this).text().toUpperCase()[0] == input;
}).show();
};
And those 2 functions you can just call in the places where you need it.

jQuery .toggle woes

My 1st question on here so I'll try to be as concise as possible.
I have a series of nav elements, some of which have nav sub-elements. My basic structure is:
<nav role="navigation" class="primary-nav main-nav">
<ul>
<li>home</li>
<li class="about-item">about</li>
<li class="study-item">study</li>
<li class="apply-item">apply</li>
<li>people</li>
<li>shows</li>
<li>contact</li>
</ul>
</nav>
<!-- secondary navs -->
<!-- about -->
<nav role="navigation" class="sec-nav sec-nav-about">
<ul>
<li>history</li>
<li>facility</li>
<li>alumni</li>
<li>friends</li>
<li>patrons</li>
<li>singers</li>
</ul>
</nav>
<!-- study -->
<nav role="navigation" class="sec-nav sec-nav-study">
<ul>
<li>foundation</li>
<li class="study-undergrad-item">undergrad</li>
<li class="study-postgrad-item">postgrad</li>
<li>part time</li>
<li>exams</li>
<li>saturday school</li>
<li>sunday school</li>
<li>summer school</li>
</ul>
</nav>
<!-- apply -->
<nav role="navigation" class="sec-nav sec-nav-apply">
<ul>
<li>loans</li>
<li>auditions</li>
<li>fees</li>
<li>exams</li>
<li>saturday school</li>
<li>sunday school</li>
<li>summer school</li>
</ul>
</nav>
(I know these lists could - and should - be nested but this is code I've inherited rather than written myself and I don't want to screw with anything else that might be in the styles).
So - what I want is when the 3rd, 4th and 5th main-nav items are clicked, their corresponding submenu animates using margin-left.
I'm currently using jQuery .toggle() to try and achieve this effect. Here is my jQuery:
$(document).ready(function(){
$('.main-nav .about-item a').toggle (
function(){
$('.sec-nav-about').animate({marginLeft: "480"}, 500);
},
function(){
$('.sec-nav-about').animate({marginLeft: "-250"}, 500);
});
$('.main-nav .study-item a').toggle (
function(){
$('.sec-nav-study').animate({marginLeft: "480"}, 500);
},
function(){
$('.sec-nav-study').animate({marginLeft: "-250"}, 500);
});
$('.main-nav .apply-item a').toggle (
function(){
$('.sec-nav-apply').animate({marginLeft: "480"}, 500);
},
function(){
$('.sec-nav-apply').animate({marginLeft: "-250"}, 500);
});
});
Up to this point, its fine. However, I cannot get beyond this point. I have no idea how to re-work the code to achieve the following:
1) When each main menu item is clicked, if it has a sub-menu and if its not already showing, then the sub-menu animates out (this is working fine).
2) If a sub-menu is already showing, then when its main menu item is clicked then the sub menu animates back in until its not showing (this is also working).
3) If a sub menu is showing and another sub menu item is clicked, the first sub-menu animates back in until its not showing and the new sub-menu animates out. This not working.
I have attempted to add/remove an .active class to each sub-menu like so (just one here for illustrative purposes but all three sub-menus have this applied to them):
$('.main-nav .about-item a').toggle (
function(){
$('.active').animate({marginLeft: "-250"}, 500).removeClass('active');
$('.sec-nav-about').animate({marginLeft: "480"}, 500).addClass('active');
},
function(){
$('.sec-nav-about').animate({marginLeft: "-250"}, 500).removeClass('active');
});
});
Then what happens is that, it seems to work and then after awhile, it stops removing/adding the .active class. I double checked in Chrome's Element Inspector and can see it (not) happening. I need to click the links twice to get the toggle() to work and drive the animation.
Any ideas/suggestions/solutions would be very gratefully appreciated.
(edited for spelling errors).
Thanks,
Will Moore's answer explains why your current method doesn't work. The following should fix your problem. Using the regex on the className property means that we can apply this to all items in your list without having to set each one up individually.
Also, note that we query the 'sub menus to hide' before adding the .active class to the currently selected sub-menu; this avoids hiding it as soon as we show it.
$('.main-nav li').click(function() {
var itemType = this.className.match(/(^| )([^ ]+)-item( |$)/);
if(itemType != null) {
itemType = itemType[2];
}
$secNavItem = $('.sec-nav-' + itemType);
$subMenusToHide = $('.active');
if(!$secNavItem.hasClass('active')) {
$secNavItem
.addClass('active')
.animate({marginLeft: "480"}, 500);
}
$subMenusToHide
.animate({marginLeft: "-250"}, 500)
.removeClass('active');
});
You can see it working in this fiddle: http://jsfiddle.net/ET475/23/
When you click 'Study' it SHOWS the study submenu.
Then you click the 'About' and it HIDES the study menu (shows the about menu).
Now you click 'Study' again. This is only the second click on the study button, so it's going to do the opposite of the last time you clicked it: ie it's going to HIDE the study submenu when you want it to show the study menu.
This works for me:
$('.main-nav .about-item a').click (function(){
var $submenu = $('.sec-nav-about');
// if the submenu you want isn't showing...
if (!$submenu.hasClass('active')) {
// if any other submenu is showing, hide it...
if ($('.active').length > 0){
$('.active').animate({marginLeft: "-250"}, 500, function(){
// ...show submenu AFTER previous submenu is hidden
$submenu.animate({marginLeft: "480"}, 500).addClass('active');
}).removeClass('active');
} else {
// no submenus showing: simply display
$submenu.animate({marginLeft: "480"}, 500).addClass('active');
}
}
});

js 'toggle' or 'hover' function?

I don't want to use the toggle, what would I need to use to get the following nav structure to stay put when main link is hovered over?
Current js:
<script type="text/javascript">
$(document).ready(function(){
$(".downservices").hover(function(){
$(".servicesdropped").toggle("fast");
});
});
</script>
Sample page
(Notice that when the submenu pops up, I cannot click on the links, as the submenu fades away)
If you aren't fussed about animation, and you wish to use JQuery you can toggle the CSS visibility rule on the class.
$(document).ready(function()
// Make sure the item is hidden initially, best to do
// this in CSS.
$(".servicesdropped").css("visibility", "hidden");
{
$(".downservices").hover(function()
{
$(".servicesdropped").css("visibility", "display");
},
function()
{
$(".servicesdropped").css("visibility", "hidden");
});
});
Using visiblity means the element will still consume the space it does in the DOM but does not display making sure the structure and positioning of other elements surrounding it are left in tact. The downside is that animations such as fadeIn() and fadeOut() will not work.
Your html markup architecture of menu should like this:
<ul>
<li class="downservices">GUYS
<div class="servicesdropped" style="display: none;">
<ul class="middle">
<h3>Shirts & Tanks:</h3>
<li>MuSkull</li>
<li>Bamboo Athletic Tank</li>
<li>Thin Strap Tank</li>
</ul>
<ul class="right">
<h3>Other Stuff:</h3>
<li>Shorties</li>
<li>Hoodies</li>
<li>Socks</li>
<li>Hats</li>
</ul>
</div>
</li>
<li>products</li>
<li>portfolio</li>
<li>contact</li>
</ul>
And in the script use this:
$(document).ready(function(){
$("li.downservices").hover(function()
{
$(this).find(".servicesdropped").slideDown("fast");
},
function()
{
$(this).find(".servicesdropped").slideUp("fast");
});
});
use like this
<script type="text/javascript">
$(document).ready(function(){
$(".downservices").hover(function(){
$(".servicesdropped").slideDown();
});
});
</script>
for hover out the menu disappear use this
<script type="text/javascript">
$(document).ready(function(){
$(".downservices").hover(
function(){
$(".servicesdropped").slideDown();
},
function(){
$(".servicesdropped").slideUp();
}
);
});
</script>

show/hide a link if certain jquery ui tab is selected

When #my-text-link is clicked, i need to select tab 5 and when tab 5 is selected i need to hide #my-text-link. hope this makes sense, heres the code, and also what I have done so far, please feel free to show me a better way. Thanks in advance
var $tabs = $('.tabbed').tabs(); // first tab selected
$('#my-text-link').click(function() { // bind click event to link
$tabs.tabs('select', 4); // switch to third tab
$('#my-text-link').hide();
return false;
});
<ul>
<li class="one"></li>
<li class="two"></li>
<li class="three"></li>
<li class="four"></li>
<li class="five"></li>
</ul>
<div id="tabs-1"></div>
<div id="tabs-2"></div>
<div id="tabs-3"></div>
<div id="tabs-4"></div>
<div id="tabs-5"></div>
As far as I can see from your code, you've already managed to open a tab when the link is clicked. Here's how you hide the link when user opens the tab:
$(".tabbed").tabs({
select: function(event, ui) {
var tabId = ui.panel.id.substring(5);
if (tabId == 5) {
$('#my-text-link').hide();
}
};
})
Hope this helps

Categories