jQuery .toggle woes - javascript

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');
}
}
});

Related

Stop slide in javascript

I used this parallax slider http://codepen.io/suez/pen/ByvKXE in my project.
Then I added a hover menu on the top of the page.
<ul class="menu">
<li class="list-menu fa-home"></li>
<li class="list-menu fa-suitcase"></li>
<li class="list-menu fa-flask"></li>
<li class="list-menu fa-user"></li>
<li class="list-menu fa-contact"></li>
</ul>
I would like to stop parallax slider when I put my mouse on the menu to click on the buttons.
How could I do that ?
Thanks for answer.
Have a look at http://codepen.io/anon/pen/YwGjNd. I have made following changes.
stopAutoSlide : variable to allow or block autoslide
mouseenter, mouseleave: events to change stopaAutoSlide state
if (!stopAutoSlide): to change current slide only if stopAutoSlide is false.
I hope this helps.
$(document).on("mouseenter", ".slider-pagi", function() {
stopAutoSlide = true;
});
$(document).on("mouseleave", ".slider-pagi", function() {
stopAutoSlide = false;
});

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.

jQuery tooltip menu does not hide properly

I'm trying to do a homegrown jQuery tooltip menu, as I don't really need all of the functionality (and overhead) of a plugin.
My site features a typical top menu with some items that need dropdown/tooltip submenus. Markup is as follows:
<ul class="topmenu">
<li class="topmenu" id="flink">
Link Text For Submenu 1
<div id="fmenu" style="display: none;" class="submenu">
Submenu Link 1<br>
Submenu Link 2<br>
Submenu Link 3<br>
Submenu Link 4<br>
</div>
</li>
<li class="topmenu">About</li>
<li class="topmenu">Contact Us</li>
<li class="topmenu" id="ulink">
Link Text For Submenu 2
<div id="umenu" style="display: none;" class="submenu">
Submenu Link 1a<br>
Submenu Link 2a<br>
Submenu Link 3a<br>
Submenu Link 4a<br>
</div>
</li>
</ul>
And here is the jQuery I'm using:
$("#ulink").hover(function(){
$('#fmenu').slideUp(300);
$('#umenu').slideDown(300);
}, function(){
var link = $(this);
window.setTimeout(function(){
// $('#umenu').slideUp(300);
}, 800);
});
$("#umenu").hover(function(){
$('#fmenu').slideUp(300);
$('#umenu').slideDown(300);
}, function(){
var link = $(this);
window.setTimeout(function(){
$('#umenu').slideUp(300);
}, 800);
});
$("#flink").hover(function(){
$('#umenu').slideUp(300);
$('#fmenu').slideDown(300);
}, function(){
var link = $(this);
window.setTimeout(function(){
// $('#fmenu').slideUp(300);
}, 800);
});
$("#fmenu").hover(function(){
$('#umenu').slideUp(300);
$('#fmenu').slideDown(300);
}, function(){
var link = $(this);
window.setTimeout(function(){
$('#fmenu').slideUp(300);
}, 800);
});
This almost gives me what I need. If I mouse over either of the main links, the correct submenu slides open - and if the other submenu is currently open, it slides closed. So far, so good.
If I roll the mouse down to a submenu, it stays open for as long as the mouse is over any portion of it. Once the mouse moves out of the submenu, it slides closed after a short delay. Perfect.
However, if I simply move the mouse off of a main link WITHOUT either mousing over the other main link or the created submenu (say, I move the mouse to the side, then around the submenu), then the subenu will stay open until the end of time (or the browser window is refreshed, whichever comes first).
You note that I have commented out the slideUp() portion related to the parent link LI elements, as they would slide my submenu up once the mouse left the parent link, even if I had moused over the appropriate submenu. This behavior obviously made the menus unusable, whereas now they are simply slightly annoying.
What stupid obvious solution am I missing?
Thanks for your help.
After looking into all sorts of answers - stop(true, true), playing with classes, etc, I finally settled on a kludgy solution that does at least work.
I have set up a hidden field for each submenu. On page load, this the value is set to zero.
On mouseover of the submenu, the hidden field is set to a value of 1. On mouseout of the submenu, the hidden field's value is set to 0.
I have re-enabled the mouseout portions of the hover code on the links themselves, but added an if statement to them. If the hidden field is set to zero (i.e. the user is not currently moused over the submenu), then the submenu slides up. If the hidden field is currently set to one (the user is moused over the submenu), then nothing happens.
HTML:
<input type="hidden" id="fph" value="0">
<input type="hidden" id="uph" value="0">
<ul class="topmenu">
<li class="topmenu" id="flink">
Link Text For Submenu 1
<div id="fmenu" style="display: none;" class="submenu">
Submenu Link 1<br>
Submenu Link 2<br>
Submenu Link 3<br>
Submenu Link 4<br>
</div>
</li>
<li class="topmenu">About</li>
<li class="topmenu">Contact Us</li>
<li class="topmenu" id="ulink">
Link Text For Submenu 2
<div id="umenu" style="display: none;" class="submenu">
Submenu Link 1a<br>
Submenu Link 2a<br>
Submenu Link 3a<br>
Submenu Link 4a<br>
</div>
</li>
</ul>
And the updated jQuery:
$("#ulink").hover(function(){
$('#fmenu').slideUp(300);
$('#umenu').slideDown(300);
}, function(){
var link = $(this);
window.setTimeout(function(){
if($('#uph').val()==0){
$('#umenu').slideUp(300);
}
}, 800);
});
$("#umenu").hover(function(){
$('#uph').val(1);
$('#fmenu').slideUp(300);
$('#umenu').slideDown(300);
}, function(){
var link = $(this);
window.setTimeout(function(){
$('#umenu').slideUp(300);
$('#uph').val(0);
}, 800);
});
$("#flink").hover(function(){
$('#umenu').slideUp(300);
$('#fmenu').slideDown(300);
}, function(){
var link = $(this);
window.setTimeout(function(){
if($('#fph').val()==0){
$('#fmenu').slideUp(300);
}
}, 800);
});
$("#fmenu").hover(function(){
$('#fph').val(1);
$('#umenu').slideUp(300);
$('#fmenu').slideDown(300);
}, function(){
var link = $(this);
window.setTimeout(function(){
$('#fmenu').slideUp(300);
$('#fph').val(0);
}, 800);
});
Works like a charm.
Since the submenus are part of the li (you call it "link"), it makes sense to just have the slide up on li out. I'm not seeing any problem with the submenu sliding back up while you are moused over it. Care to elaborate on what browser and version you're seeing this?
$("#ulink").hover(function(){
$('#fmenu').slideUp(300);
$('#umenu').slideDown(300);
}, function(){
var link = $(this);
window.setTimeout(function(){
$('#umenu').slideUp(300);
}, 800);
});
$("#flink").hover(function(){
$('#umenu').slideUp(300);
$('#fmenu').slideDown(300);
}, function(){
var link = $(this);
window.setTimeout(function(){
$('#fmenu').slideUp(300);
}, 800);
});
http://jsfiddle.net/vau9jtos/1/
EDIT:
http://jsfiddle.net/vau9jtos/2/
absolutely positioned the menu
static positioned submenu
submenu container with width of 0 to keep main navbar from expanding

How to dynamically add a class to li item and change its background color using javascript and css

Here I have a list, what I want to do is I need to change the list ( li ) background color to different one after click on a specific list item. the thing is once it click on the link page will be redirected and refresh. please can me suggest a solution for to get this done?
<div id="main-menu">
<ul id="main-menu-list">
<li id="menu-home">Home</li>
<li id="menu-profile">My Profile</li>
<li id="menu-dashboard">My Dashboard</li>
<li id="menu-search">Search</li>
</ul>
</div>
what i did for this :
Java Script :
var make_button_active = function()
{
//Get item siblings
var siblings =($(this).siblings());
//Remove active class on all buttons
siblings.each(function (index)
{
$(this).removeClass('active');
}
)
//Add the clicked button class
$(this).addClass('active');
}
//Attach events to menu
$(document).ready(
function()
{
$("#main-menu li").click(make_button_active);
}
)
CSS :
#main-menu-list li.active {
background: #0040FF;
}
It's a little difficult to tell exactly what you want to do, but here's some quick and dirty (and untested) code:
/// when we click on an `a` tag inside the `#main-menu-list`...
$('#main-menu-list').on('click', 'a', function(e) {
// stop the link from firing
e.preventDefault();
e.stopPropagation();
// change the list item's background to green
$(this).closest('li').addClass('myClassName').css('background-color', 'green');
// do anything else, e.g. load in pages via ajax...
});
You could use CSS to apply the green background color, instead of jQuery:
.myClassName { background-color: green; }
This will stop the page from navigating, and I don't know if that's your intention. If you want to check the currently-loaded page against the menu to find the current item, you could do this (on page load) instead:
var currentPage = window.location.pathname;
$('#main-menu-list').find('a[href^="' + currentPage + '"]').closest('li').addClass('active');
EDIT:
Your amended Javascript code can be simplified to the following:
$('#main-menu li').on('click', 'a', function (e) {
e.preventDefault();
e.stopPropagation();
// only do the following if the clicked link isn't already active
if(!$(this).closest('li').hasClass('active')) {
$(this).closest('ul').find('.active').removeClass('active');
$(this).closest('li').addClass('active');
// load in your content via ajax, etc.
}
});
JSFiddle example
For each page you can add a class to the current list item that has "where the user is"..
CSS:
.selectedItem{
background-color: orange;//whatever color your want for the selected tab..
}
Then for each of your pages,
say you're in Dashboard.html
your menu code will look like:
<div id="main-menu">
<ul id="main-menu-list">
<li id="menu-home">Home</li>
<li id="menu-profile">My Profile</li>
<li id="menu-dashboard" class="selectedItem">My Dashboard</li>
<li id="menu-search">Search</li>
</ul>
</div>
in profile.html:
<div id="main-menu">
<ul id="main-menu-list">
<li id="menu-home">Home</li>
<li id="menu-profile" class="selectedItem">My Profile</li>
<li id="menu-dashboard">My Dashboard</li>
<li id="menu-search">Search</li>
</ul>
</div>
and so on..
You need to change the background color when the document is loaded (i.e. in document.ready).
Then you need a mechanism to connect the currently loaded page to one of your list items.
$(document).ready(function(){
//get the url from the current location or in some other way that suits your solution
//perhaps use window.location.pathname
var moduleId = "dashboard" // hardcoded to dashboard to make the point :);
$("#menu-"+moduleId).css("background-color", "#ccc");
});
http://jsfiddle.net/9JaVn/1/

jQuery: Delay showing of a dropdown menu content

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.

Categories