I have created a responsive menu that breaks at 480px and below. I have it to where the following reacts if:
The user clicks on a the "Menu" link.
The menu slideToggles out.
The sub-menus slideToggle out onClick as well.
But you cannot click on any of the pages.
Does this have something to do with the return false?
You may view the example here: http://www.stlredtails.com/construction/
You may need to resize the browser at or belw 480px to see the responsive navigation in action.
Here is the jQuery for the navigation:
jQuery(".navigation ul").hide();
jQuery("#navigation").click(
function() {
jQuery(this).siblings("ul").slideToggle(150, "swing");
return false;
}
);
jQuery(".navigation > ul > li").click(
function() {
jQuery(this).children("ul").slideToggle(150, "swing");
return false;
}
);
Thank you all!
The problem comes from the return false. When you're clicking the links, you're also clicking the ancestors li and ul. Before the link "activates" the functions bound to the ancestors click event execute. Since they return false the default browser behavior (navigating away) is prevented.
There are better solutions for this kind of menu behavior, but using what you already you have (and assuming you won't be changing your html) you can simply add the following to your javascript:
$('.navigation').on('click', 'a:only-child', function(e) {
e.stopPropagation();
});
This searches for all links in the navigation menu that are the only child of their parents (which in this case, happen to be the links you want to continue working as links) and prevents the ancestors click events from executing - the return false shouldn't happen anymore.
Related
I have an off canvas navigation menu (classname that is enabled via hover-over using jQuery on my Wordpress site. It is, as it should be, not visible on page load.
For the mobile version, I want the same nav menu to be activated by clicking on a menu icon (that I've given two classes, in this order: mobile-nav-toggle show-nav-mobile). The toggle method seems to only work for a vertical toggle. My solution to replicating the same animation on click rather than hover, is by using the toggleClass method on the icon to toggle between a classname that opens the menu nav (show-nav-mobile) and closes it (hide-nav-mobile) Using the below code:
jQuery(".show-nav-mobile").click(function(){
jQuery(".offcanvasmainnav").animate({left:'0px' }, 250);
});
jQuery(".mobile-nav-toggle").click(function(){
jQuery(".mobile-nav-toggle").toggleClass("show-nav-mobile hide-nav-mobile");
});
jQuery(".hide-nav-mobile").click(function(){
jQuery(".offcanvasmainnav").animate({left:'-640px' }, 250);
});
That doesn't seem to do the job though. The jQuery opens the offcanvasmain div just fine, but doesn't close it again.
What is wrong with my approach?
I assume your element initially looks somewhat like this:
<nav class="mobile-nav-toggle hide-nav-mobile">...</nav>
This means that
a) Both these click handlers will always run when clicking, no matter if the element still has the class hide-nav-mobile:
jQuery(".mobile-nav-toggle").click(function(){
jQuery(".mobile-nav-toggle").toggleClass("show-nav-mobile hide-nav-mobile");
});
jQuery(".hide-nav-mobile").click(function(){
jQuery(".offcanvasmainnav").animate({left:'-640px' }, 250);
});
jQuery finds the element at the moment you define the click handler; it doesn't recheck if the element still has this class when clicking later.
b) This never attaches a click handler:
jQuery(".show-nav-mobile").click(function(){
jQuery(".offcanvasmainnav").animate({left:'0px' }, 250);
});
because at the time of calling jQuery(".show-nav-mobile") it cannot find any element with that class.
To fix it, do this all in a single click handler:
jQuery(".mobile-nav-toggle").on('click', function(){
const that = jQuery(this);
that.toggleClass("show-nav-mobile hide-nav-mobile");
jQuery(".offcanvasmainnav").animate({left: that.hasClass('show-nav-mobile') ? '0px' : '-640px' }, 250);
});
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!
Ok... So I have this drop down menu working as I'd like... however I'm trying to figure out how to revert the function back to it's original state after a menu item is clicked.
So first when you trigger the function it does & works great the following:
It swaps out .menu_hide and .lockscreen for .menu_show and .lockscreen_on.
// show and hide mobile menu
$('#triggerMobileMenu').click(function(e) {
e.preventDefault();
// Toggle all 4 classes off or on
$('#mobileMenu').toggleClass('menu_hide menu_show');
$('#mobileScreen').toggleClass('lockscreen_off lockscreen_on');
But now I'm trying to add another piece that says once a menu item is clicked, close the menu and swap the classes back to their original state from .menu_show and .lockscreen_on, to .menu_hide and .lockscreen_off.
$('#mobileMenu ul li a').on('click',function(){
$('#mobileMenu').toggleClass('menu_show menu_hide')({ autoCloseOnClick: true });
$('#mobileScreen').toggleClass('lockscreen_on lockscreen_off')({ autoCloseOnClick: true });
});
});
I should also note that on the same page a scroll to id# may be happening vs just simply taking you to the new url/page. Either case will happen though.
I think that you're making this too complicated. Use the same event handler for both a#triggerMobileMenu and ul#mobileMenu li a since you're having them do the same thing (toggle the visibility of the menu and another element).
$('a#triggerMobileMenu, ul#mobileMenu li a').on('click', function(evt){
evt.preventDefault();
$('#mobileMenu').toggleClass('menu_hide menu_show');
$('#mobileScreen').toggleClass('lockscreen_off lockscreen_on');
});
If you need to know which element was clicked in the event handler, evt.target is available:
if( $(evt.target).is($('a#triggerMobileMenu')) ) {
// do stuff
}
See http://jsfiddle.net/Mph6t/3/
I think it is working as intended. I had to fix some id names that may have been switched in the translation to jsfiddle. Here's a working one as far as I can tell. This leaves the somename2 div still showing. I assume that is going to be blank and just for locking the screen right?
I also changed the link to a new tab for testing purposes. FYI.
Relevant changes are:
$('#somename1 ul li a').on('click',function(){
$('#somename1').toggleClass('menu_show menu_hide')({ autoCloseOnClick: true });
$('#somename2').toggleClass('lockscreen_on lockscreen_off')({ autoCloseOnClick: true });
});
I'm building a website where some elements in the navigation menu have a submenu. These submenus are shown when the mouse hovers over the element, but of course on mobile I cannot do that since there is no actual hover. A tap means a click, and that follows the link. I hoped on a simple solution but it doesn't work on my mobile device...
Here's a code snippet inside a loop, this is a menu item (li) that contains a submenu (ul):
$(this).find("a").on("mouseenter focusin click", function(e) {
if(submenu.css("display") != "block") {
e.preventDefault(); //should work on mobile
}
submenu.stop().css('display', 'block').animate({
top: 1.2em,
opacity: 1
}, 200);
});
Now I test this in Firefox. In normal use, you cannot actually click the menu item before the submenu comes out because display becomes block as soon as the mouse hovers over it. So in web console I type in:
$("#nav > ul > li:first-child > a").click()
This gives the expected behaviour. the submenu comes out but the link isn't followed. On mobile, the link is still followed... What gives?
Update
I just entered two alert statements. One that says the event type first thing in the handler, and one that says "preventing default" just before e.preventDefault. On my mobile browser (Dolphin browser for Android) it gives the following on a tap of the menu item:
Event is mouseenter
Preventing default
Event is click
Naturally, when the first event fired is "mouseenter", the default will not be prevented for click as that is the point where the menu shows up. In other words, I would need to make sure that the first mouseenter does show the menu but a click isn't fired... I could check the top css property for that, but I wonder if there is another way.
I got it working by adding another check to see if the submenu is at the proper position, rather than using the value of display.
$(this).find("a").on("mouseenter focusin click", function(e) {
if(e.type == "click" && submenu.css("top") != "1.2em") {
e.preventDefault();
}
submenu.stop().css('display', 'block').animate({
top: 1.2em,
opacity: 1
}, 200);
});
OK, so. I'm trying to create a dropdown menu of sorts using fadeToggle().
http://westrock.juggernautwebsites.com/ is where the site is currently located.
As you can see, when a user selects 'Properties', the fadeToggle occurs. However, after the dropdown occurs, and a user wants to select a li from the properties dropdown, they are unable to (I know I have return false; set, but that was supposed to be for the original ul, no?)
As well, when the child items are displaying, if you hover over About, the :hover effect displays on the Properties child li.
I'm boggled. Any help, greatly appreciated.
$('#menu-item-13').click(function() {
$(this).children('ul').fadeToggle({
duration: 200
});
return false;
});
*EDIT
I feel like I need to restrict the css and jQuery from affecting children list-items and a, but I don't know how to do this. I thought children only went one level down the DOM, and since I selected 'ul', the function wouldn't affect list-items...
Your example doesn't work at all for me, but if I'm understanding you correctly, you want the child ul to not be affected by the click handler attached to the parent. You can do this:
$('#menu-item-13 > ul').click(function(e){
e.stopPropagation();
// ... do your thing
});
This basically stops the click on the ul from bubbling up to the parent #menu-item-13. Because of this, the fadeToggle will also not trigger from the click on the ul, so if that is still needed you will have to add it to the ul's click.
Thanks for everyone's help! Here's what I eventually ended up using.
$('#primary li').hover(function() {
$(this).children('ul').fadeToggle({
duration: 200
});
});
$('menu-item-54').click(function() {
return false;
});
What I was trying to accomplish upon hover (or click), the subnav would expand open.