jquery - sub menu is hidden on mouseout of main menu - javascript

This seems like a pretty easy one, but I couldn't solve my issue by reading the related questions here on SO.. so here's mine. I have:
<ul class="main-menu">
<li>Letters</li>
<li>Numbers</li>
</ul>
<ul class="sub-menu hidden">
<li>A</li>
<li>B</li>
<li>C</li>
</ul>
I want .sub-menu to appear on mouseover of .main-menu, and keep visible while the mouse is over both .main and sub.
$(".main-menu, .sub-menu").hover(
function(){
$('.sub-menu').hide().removeClass('hidden').slideDown('fast');
}, function(){
$('.sub-menu').slideUp('fast');
}
);
But mouseout is fired when I mouseout of main-menu, even though I mouseout of it into sub-menu, so the sub-menu is hidden.
Any suggestions? Restructuring the HTML is not an option, though.

The following assumes you have a second sub-menu to go with the "Numbers" main-menu item, something like I've shown here: http://jsfiddle.net/aY7wW/ - and further assumes that when you said "Restructuring the HTML is not an option" you meant that I couldn't even suggest adding attributes to associate each sub-menu with its main-menu item. To work within this restriction I've used the main-menu li element index to relate to the sub-menu ul element index (obviously this works only if the sub-menus are defined in the same order as the corresponding main-menu items). If you could add some id attributes or something it would simplify the code somewhat, but anyway:
var timerId,
$mainMenuItems = $(".main-menu li"),
$subMenus = $(".sub-menu");
$mainMenuItems.hover(
function(){
clearTimeout(timerId);
$subMenus.slideUp('fast');
$($subMenus[$mainMenuItems.index(this)]).hide()
.removeClass('hidden')
.slideDown('fast');
}, function(){
var i = $mainMenuItems.index(this);
timerId = setTimeout(function(){$($subMenus[i]).slideUp('fast');},500);
}
);
$subMenus.hover(
function() {
clearTimeout(timerId);
},
function() {
$(this).slideUp('fast');
}
);
The basic idea is to use setTimeout() to delay hiding the sub-menu on mouseout from the main-menu. This gives you time to move the mouse over the sub-menu, and if you do the timeout is cleared so it won't be hidden. Then when you move the mouse off the sub-menu it is hidden. But allowing for movement of the mouse just between the different main-menu items, on initial hover we also clear any outstanding timeout and hide previously shown sub-menus so that only the correct sub-menu will show. I've used a delay of 500ms, but obviously you can set that to whatever feels natural for you.
Working demo: http://jsfiddle.net/aY7wW/

Try putting both the main and sub menus in a div, and put the hover event on the div.

How about something like:
$(".main-menu").mouseover(function () {
$('.sub-menu').slideDown('fast').click(function (){
$(this).slideUp('fast');
});
});

Related

jQuery - on hover leave keep div visible

Sorry for the question title, I really didn't know how to summarise it a short description.
Essentially I have got a <ul> which has my navigation links. However in one of the <li> links is my custom dropdown shopping basket to give the user a preview of their items.
Now when I hover over the element , I want it to change the basket from display:none to display:block making it visible. But with my code, as soon as I leave the hovered element to click on an item. The dropdown disappears because I'm no longer hovering over the element I defined in my jQuery hover function.
For example (quick dummy code)
$('.hover-on-me').hover(function(){
$('.hover-open').show();
},function(){
//This right here hides the dropdown
$('.hover-open').hide();
});
Now I'm not the bets at javascript/jQuery. I have tried to say in the function, if the mouse is still on the navigation bar , don't hide it or if the mouse is on the shopping basket then don't hide it. I thought this would let me move from the hover element, past the navigation bar and onto the drop down menu but it doesn't work. as the element then stays open and doesn't close when i leave the area.
Here is a simple jsfiddle demonstrating my problem.
Thanks!
I think there is mistake in your class name only.
jQuery Code :-
$('.hover-on-me').hover(function(){
$(this).parent("li").addClass("active");
}, function(){
$(this).parent("li").removeClass("active");
});
Add this to you CSS Code :-
ul li.active{display:inline-block;}
ul li.active .hover-open, ul li .hover-open:hover{display:block;}
Can you please try these.
the hover syntax will look like this.. $(selector).hover(inFunction,outFunction)
and try to modify your script like this..
$('.hover-on-me').hover(
function(){
$('.hover-open').show();
},
function(){
if(!$('ul').is(":hover") || !$('.hover-open').is(":hover")){
$('.hover-open').hide();
}
}
);
OR
use mouse event function..
$( ".hover-on-me" )
.mouseenter(function() {
$('.hover-open').show();
});
$( ".hover-open" )
.mouseleave(function() {
$('.hover-open').hide();
});
for further details refer here..https://api.jquery.com/hover/#hover2 and https://api.jquery.com/category/events/mouse-events/

Animate icon don't take his original position on toggle click

I have a accordion menu which have for each parent menu a icon, and this icon is animated with css transition and transform. I added a class with a if condition to the click event. The problem is that when I click for example on Menu1, the icon animation does very well, but if I click directly on Menu2, the menu2 dropdown appear but icon from the menu1 don't take his original position.
This problem applies to each icon in each menu/submenu, I thinks that I have a mistake in my code.
$(document).ready(function() {
// Icons effect
$('#mw_nav .toggle').click(function() {
if($(this).hasClass('rotate_close'))
{
$(this).addClass('rotate_open').removeClass('rotate_close');
}
else {
$(this).addClass('rotate_close').removeClass('rotate_open');
}
});
// Toggle Menu Items
$(function () {
$("#m_nav > ul ul").hide();
$('#m_nav .toggle').click(function (e) {
e.preventDefault();
e.stopPropagation();
var $parentli = $(this).closest('li');
$parentli.siblings('li').find('ul:visible').slideToggle(400);
$parentli.find('> ul').stop().slideToggle(400);
$(this).remove;
});
});
});
FIDDLE
Any help would be appreciated
There are 2 issues I see with your code. The first is a recommendation to NOT have $(function() { // your code }) inside of $(document).ready(). $(function() {}) is actually just shorthand for $(document).ready() so you are adding code you do not need.
The second is an issue with your logic.
$('#mw_nav .toggle') and $('#m_nav .toggle') click listeners are essentially adding a click listener on the same exact element, but both run different logic. When the $('#mw_nav .toggle') click listener is getting called it checks for a class to exist to decide what class it needs to remove and add. When $('#m_nav .toggle') click listener is getting called it calls a slideToggle function on the current nested <ul> regardless if another menu is opened or closed and there is no check in place of whether or not the rotate_open/rotate_close classes exist allowing for the classes to get swapped. There is no relation between the swapping of rotate_open/rotate_close classes and the logic that slideToggles <ul> up/down.
UPDATE
I have edited your code and made updates that will now work seen here: https://jsfiddle.net/vhfn0q5a/9/
I have added a class of .top_level to the top level items in your HTML. I use this as a way of differentiating the top level <li> from the sub menus. Next, at the end of the click event listener I check to see if the .toggle element clicked is a top level element, if so I target all top level elements that are not the current selected and make sure they have the .rotate_close class.
$(function() {}) shorthand reference
Use this code in your first click handler:
$('#mw_nav .toggle').click(function() {
$(this).toggleClass('rotate_close rotate_open');
if ($('#mw_nav .toggle').not(this).hasClass('rotate_open')) {
$('#mw_nav .toggle').not(this).removeClass('rotate_open').addClass('rotate_close');
}
});
I've updated your FIDDLE with an working example.
Cheers!

Toggle view of list elements on touch devices

I'm trying to deal with some sort of toggle view effect on a HTML unordered list.
What I'm trying to do is switch DIV views inside a LI, using jquery (not jquery mobile), when I touch it on a touch screen device and restore view when tapping somewhere else outside the current LI.
this is a HTML example:
<ul>
<li class="item1">
<div class="div1">Info</div>
<div class="div2" style="display:none;">Tools</div>
</li>
<li class="item2">
<div class="div1">Info</div>
<div class="div2" style="display:none;">Tools</div>
</li>
<li class="item3">
<div class="div1">Info</div>
<div class="div2" style="display:none;">Tools</div>
</li>
</ul>
So basically if I tap on "item2", "div1" should hide and "div2" should be visible, inside "div2" are some buttons that you can interact with. But then, when I touch outside "item2", "div1" should be visible again and "div2" should hide.
I tried using nouseenter and mouseleave with jquery, but it causes a mess when you try to scroll or tap the other LI elements in the same list, also tried using toggle, but so far no luck. Now I can't find a simple but effective way to achieve what I want, hope you guys can help me with this.
Thanks!
EDIT:
Here is a working example that doesn't work properly on touch devices http://jsfiddle.net/T5HMt/44/
As per my understanding you want corresponding div2 to show and to hide div1 when li is tapped (example- On tap event on "item2", "div1" of "item2" should hide and "div2" of "item2" should be visible). And you want to show "div1"and hide "div2" only when user taps somewhere outside the li (outside any LI mentioned in your question).
Please check this code if it helps you.
$(".item1, .item2, .item3").click(function(){
$(this).children(".div2").css("display", "block");
$(this).children(".div1").css("display", "none");
});
$(document).click(function(e) {
var target = e.target;
if (!$(target).parents().is('.item1') && !$(target).parents().is('.item2') && !$(target).parents().is('.item3')) {
$(".div2").css("display", "none");
$(".div1").css("display", "block");
}
});
Working fiddle - http://jsfiddle.net/Ashish_developer/5jpyzkmt/
In the fiddle I have given border to LI just to illustrate it.
Well it looks like I found a way to solve my own problem with a solution very similar to the one provided by Tushar Raj. Instead of displaying the hidden div on mouse over I did it on a click event and then hide it on mouse leave.
The thing is that mousenter triggers two things at the same time on touchscreens, the first thing is a 'mouseenter' event and then a 'touchstart' event, so if you have links inside the div that is being displayed on the mouseenter event, they will also be 'clicked'.
$(document).on({
click: function () {
$(this).find('.main').hide();
$(this).find('.second').show();
},
mouseleave: function (event) {
$(this).find('.main').show();
$(this).find('.second').hide();
}
},'.search');
And a working example it works as expected on touch screens
Thanks to everyone for helping me out
Try hover . It should work for touch devices too .
$('.item1,.item2,.item3').on('hover',function(){
$(this).find('.div1').hide();
$(this).find('.div2').show();
},function(){
$(this).find('.div1').show();
$(this).find('.div2').hide();
});

How to temporarily disable a navigation link using jQuery

I'm still learning a bit on javascript/jquery and running into a bump. Every post I pull seems to over-complicate the process, unless it really does require all the extra code.
Here's what I'm doing:
Creating a vertical navigation menu with sliding menu's and static sub-menu's
Using HTML (5) layout with DL, DT and DD
Nav menu is using minor CSS for styling
Nav menu is using jQuery (1.8.3)
I have everything working the way I want, but because I'm picky, I want to temporarily disable the link after a menu is expanded. If I try to click the menu that is already expanded, it slides up and then back down. What I wanted to do is make it so it just doesn't react to a click if it's already expanded.
HTML of Nav Menu:
<dl class="nav2">
<dt>Thing1</dt>
<dd>
<ul>
<li>Test Def1</li>
<li>Test Def2<li>
<li>Test Def3</li>
</ul>
</dd>
<dt>Thing2</dt>
<dd>
<ul>
<li>Test Def4</li>
<li>Test Def5<li>
<li>Test Def6</li>
</ul>
</dd>
<dt>Thing3</dt>
<dd>
<ul>
<li>Test Def7</li>
<li>Test Def8<li>
<li>Test Def9</li>
</ul>
</dd>
</dl>
jQuery for Nav Menu:
$(document).ready(function() {
$("dd:not(:first)").hide();
$("dt a").click(function() {
/* was thinking the added code would go here, but I could be wrong */
$("dd:visible").slideUp("fast");
$(this).parent().next().slideDown("fast");
return false;
});
});
I've tried a few things with bind and one, but due to my confusion with writing js/jquery, I'm not finding my trick. Is there anyway possible to say something like:
$(this:active).unbind("click");
or
if ($(this).active(function() {
$(this).unbind("click");
} else {
$(this).bind("click");
)};
I know I'm probably way off, but I'm trying. Is there any way to change this into javascript/jQuery?
When the DT A is clicked -
make THIS DT / DT A not clickable;
When THIS DT / DT A is no longer expanded or visible -
make THIS DT / DT A clickable;
Thanks for the peak. Sorry if this was found somewhere. Each post I've ran into starts expanding this tiny change into several lines of code, whether attacking the CSS, longer then what seems to be needed javascript/jQuery or both. I just really want to try to keep it contained and simple (if at all possible).
You do not want to disable the click (by disabling the anchor, or unbinding the event). You want to not execute an action when the clicked element is currently selected. Do that like this:
$(document).ready(function() {
var active = $("dd:first");
$("dd").not(active).hide();
$("dt a").click(function() {
var dd = $(this).parent().next();
if (! dd.is(active)) {
active.slideUp("fast");
active = dd.slideDown("fast");
}
return false;
});
});
You could add a temporary class to a link which has been clicked, and then remove it once whatever action the event triggered is complete. Test for the class each time a link is click with hasClass, if it does, do nothing, if it doesn't, do something. I have answered a similar question here:
Suppress jQuery event handling temporarily
Here's how it would work with your code (I believe, though may need modification to suit your needs):
$(document).ready(function() {
$("dd:not(:first)").hide();
$("dt a").click(function(e) {
// Prevent link from doing default action
e.preventDefault();
if ($(this).hasClass('fired') == false) {
// Add 'fired' class to disable link
$(this).addClass('fired');
// Do some stuff
$("dd:visible").slideUp("fast");
$(this).parent().next().slideDown("fast");
// Remove 'fired' class to re-enable the link
// You may need to do this in a call back function
// If you are animating something
$(this).removeClass('fired');
}
// Use preventDefault instead of this
/*return false;*/
});
});

Set back again the current menu link to "active" once navigation through menu stops

Ok, maybe you can't understand much from the title, so I'll try to explain it a bit more in here.
Basically I have a navigation, like this:
<ul class="primaryNav">
<li class="nav1">About us</li>
<li class="nav2">Our world</li>
<li class="nav3">Active page</li>
</ul>
Now I'm on the "Active page" page and the "Active menu link" is active as you can see (the class is set manually by me on each page).
The user can navigate through that other menus (hover them) and they become active, and my "Active menu link" inactive and so on. (through jQuery)
Well, what I'm trying to do, is, once the user stops navigating through my menu, and move mouse cursor outside the navigation container (let's say), set back to "active" the "Active menu link" wich was initially active, with some timeout, maybe.
Hope I was clear enough about what I'm trying to achieve.
Thanks,
Adrian
Something like:
var resetMenu = function() {
$('li.active').attr('class','active').siblings().attr('class','inactive');
};
var to;
$('ul').bind('mouseout', function() {
window.clearTimeout(to);
to = window.setTimeout(resetMenu, 1000);
});
I'm using attr() instead of add/remove classnames here based on your example. You can alter the 1000 for more/less time to wait before "resetting" the menu.
I'm not completely clear what you want to do, but it sounds like you're looking for the jQuery hover() event, which fires when the mouse enters the matched element, and the callback function when it leaves.
$('ul.primaryNav').hover(function() {
// do stuff when the mouse enters the <ul>
},
function() {
// do stuff when the mouse leaves the <ul>
});
I suspect you might be intending to use <ul id="primaryNav"> and <li id="Nav1">, etc.—ids instead of classes to uniquely identify these elements.
What exactly // do stuff means depends on what exactly you're looking for, but probably just adding and removing an active class will do instead of using an inactive class as well.
I'm not looking for just the .hover() event from jQuery, it's little more than that.
I am already using jQuery .hover() event to add to the current hovered link the class "active" and to the others the class "inactive".
But in the Active page the "active" class from is set manually by me, and I want that to be active again when users stop navigation through my menu. I mean, when I play with the menu and hover the links it does the stuff I told you about (add class active to current, add class inactive to others) - when I mouseout the navigation area I want that the "active" class to "go" back again to the initial link who had that className when I first arrived into that page.
I have some submenus, also, wich are shown on hover, but I guess that's not so relevant for my question.
This should work. If you need explanations just comment on answer
var as;
var ul = $('ul.primaryNav').mouseout(function() {
toogle(
as.filter('.active'),
as.filter(function() {
return $(this).data('originalActive') === true;
})
);
});
as = ul.find('a');
//remember which one was original active
as.filter('.active').data('originalActive', true);
function toogle(ina, act) {
ina.removeClass('active').addClass('inactive');
act.removeClass('inactive').addClass('active');
};
as.mouseover(function() {
//make current active, inactive others
toogle(as.filter('.active'), $(this));
});

Categories