I have a horizontal menu. This sub menu is displayed outside the ul. When i hover on a specific class, I want the .sub_menu to appear. When I hover the .sub_menu, I want it to be still there.
However, when moving my mouse from to the .sub_menu, it disappears.
jQuery(document).on('click', '.mobile-sub-menu-controller', function () {
jQuery(this).siblings('.sub-menu').slideFadeToggle();
if (jQuery(this).find('i').hasClass('icon-angle-down')) {
jQuery(this).find('i').removeClass('icon-angle-down');
jQuery(this).find('i').addClass('icon-angle-up');
} else {
jQuery(this).find('i').removeClass('icon-angle-up');
jQuery(this).find('i').addClass('icon-angle-down');
}
});
In
jQuery(document).on('click', '.mobile-sub-menu-controller', function () { ..
change click to 'mouseenter', because 'mouseover' will trigger the event for every movement unit the cursor moves across the target.
I think that you can attach watcher for both elements (menu item and submenu) and decide with class you should use in both watchers.
However, is your menu has the structure like this:
<ul>
<li><i>icon<i> Text
<ul>
...
</ul>
</li>
<li><i>icon<i> Text
<ul>
...
</ul>
</li>
...
<ul>
You can use css or mouseenter/mouseleave events to toggle the menu item class to show submenu.
Be careful, if there is a gap between menu item and submenu your css or js will work incorrectly because mouse will leave menu item to the another element but not to the submenu.
If you have some additional information or questions let me know.
Also you may attach your menu html code to clarify the question.
Related
I have been working on getting a popup menu on a button.
There are 7 buttons with this menu, on the page in different containers. So far you can click the button and the menu opens.
Each menu opens with its own version of this, which works but not efficient:
$('.country-btn-portugal').click(()=>{
$(".dropdowna").toggleClass('active');
});
$('.country-btn-uk').click(()=>{
$(".dropdowna").toggleClass('active');
});
....etc... x7, one for each button menu.
I have tried to close the menu if an item is clicked but doesnt function with:
//close if menu <a> is clicked
$('#mclose').click(()=>{
$('.dropdown').removeClass('active');
});
And using the following to close the menu if an item that is not this element is clicked (does not work):
$(document).mouseup(function (e)
{
var container = $("#oclick");
if (!container.is(e.target) // if the target of the click isn't the container...
&& container.has(e.target).length === 0) // ... nor a descendant of the container
{
container.hide();
}
});
which i was hoping would also fix the issue when 1 menu is open and your next click is another menu, so you have both open.
The menu buttons will be serving separate divs (or card like boxes and are not siblings next to eachother. Hence finding it hard to compact the code. had to give each menu its own click functions.
it is a mess sorry. would be nice to see where im going wrong here.
fiddle --> https://jsfiddle.net/s4nk1zev/118/
html structure for one "card" with one "menu button".
<div class="country_card">
<span class="cc-t goth upperC">Portugal </span> <span class="cc-t goth upperC blued">Visa</span>
<div class="cc-txt">
text in here
</div>
<div class="cc-btn">
<button class="tablabel country-btn-portugal" id="portimg"></button>
<div id="mcontainer" class="dropdowna">
<a id="mclose" class="mclose" href="#home">Overview</a>
<a id="mclose" href="#about">Application Process</a>
<a id="mclose" href="#contact">Investment Options</a>
</div>
</div>
</div>
Well, this is how I would have done that.
Here is the updated fiddle
And this script would do enough
//open menu
$('.tablabel').click(function(event){
$('.tablabel').not(this).next().removeClass("active")
$(this).next().toggleClass("active")
});
//close if menu clicked
$(".dpd").click(function(e){
$(this).toggleClass("active")
})
//close if anything but menu clicked
What it does is, just listen for any click on the button and add active class to the next of it. Removing active class from all the active elements if there is any.
Secondly, you can use a class (as I've added one dpd) on the menue items to detect a click on them to close the open menu.
One more thing. Identifiers must be unique for each element you use. I've also updated them to be unique
Hope that helps
SInce your button and menu tags appear to always be siblings, if you add a common class to all your dropdowns, you can get a list of all of them more easily. Like this:
<div id="mcontainer" class="dropdown dropdowna">
Also as a suggestion, it's really not a very good idea to have duplicate ids in your document. It's against the html standard, and it can cause strange issues with getting tags by id.
Once you have a common class on all your dropdowns, you can do something like this to close all others, and toggle the one related to the button you're clicking.
function fnClick(e){
var $dd = $(this).next();
$('.dropdown').not($dd).removeClass('active');
$dd.toggleClass('active');
}
//open menu
$('.country-btn-portugal').click(fnClick);
$('.country-btn-uk').click(fnClick);
here's an update of your fiddle to demonstrate:
https://jsfiddle.net/s4nk1zev/143/
You can try using promise().done(), and reviewing the html class. This is a fiddle for you: https://jsfiddle.net/zxoLmf71/
using a promise on an element let you wait for the code to finish execution before start the new one. this is the code:
//open menu
const buttons = $('.country-btn');
const dropDownMenus = $('.dropdownmenu');
const dropDownItems = $('.dropDownItem')
buttons.click(function() {
dropDownMenus.removeClass('active');
$(this).next('div').promise().done(function() {
$(this).toggleClass('active');
});
});
//close if menu clicked
dropDownItems.click(function() {
dropDownMenus.removeClass('active');
});
Hope it helps
I get some issue when opening the menu1 dropdown and directly after mouseover the menu2 to open it without closing de menu1.
If I open the menu1 and move the cursor out from the nav to close the dropdown and then mouseover the menu2 it works fine.
If I go directly from menu1 to menu2 or inversely, the menu2 dropdown appear under the menu1 dropdown.
I thinks that I have a mistake in my html or it can be fix with a jquery function but I don't know how to solve this. I wish to add more menu, in the actually there are only two.
I hope that you understand my problem,
Any help would be appreciated
$(document).ready(function () {
var menu = $('.menu')
menu.hide();
$("#mainbutton").mouseenter(function(){
$(".menu").stop().slideDown("fast");
});
$("#nav").mouseleave(function(){
$(".menu").stop().slideUp("fast");
});
var menu2 = $('.menu2')
menu2.hide();
$("#secondboutton").mouseenter(function(){
$(".menu2").stop().slideDown("fast");
});
$("#nav").mouseleave(function(){
$(".menu2").stop().slideUp("fast");
});
});
Here the JSFiddle
I would suggest to add a general class name to all menus .menu and a specific selector for each individual menu (#menu1 or .menu1) as well as an indicator for the active state .active. this way you can simply close all .menu.active
see the following fiddle as a simple proof of concept:
https://jsfiddle.net/ad3a5qyw/2/
EDIT:
I've abstracted the fiddle so you can add data-menu attributes to the nav-items to indicate the associated menu.
I see what's going on here:
It's easy with jQuery and the code you've written already, and here's an example with a new menu item to show how easy it is: https://jsfiddle.net/xyqoj24m/2/
What's going on is that the mouseleave functions are only run when the mouse leaves the entire #nav element. So what needs to be done is handle the hiding/showing of the menus like so:
When the mouse hovers over a menu item, close all other dropdowns and show the correct one.
When the mouse leaves the dropdown or the menu item, close the dropdown.
Take a look at this Javascript and see what that means:
$("#mainbutton").mouseenter(function(){
$(".menu").stop().slideDown("fast");
$(".menu2").stop().slideUp("fast");
$(".menu3").stop().slideUp("fast");
});
$("#secondbutton").mouseenter(function(){
$(".menu2").stop().slideDown("fast");
$(".menu").stop().slideUp("fast");
$(".menu3").stop().slideUp("fast");
});
// leave the first menu dropdown
$("#mainbutton, .menu").mouseleave(function() {
$(".menu").stop().slideUp("fast");
});
// leave the second menu dropdown
$("#secondbutton, .menu2").mouseleave(function() {
$(".menu2").stop().slideUp("fast");
});
Feel free to ask questions!
I have this drop-down menu that drops down on hover normally, but on touch devices, I simply made it so that you can click to open it as well.
The problem is that it seems like the <ul> that drops down isn't completely in focus or something because I have to click the links twice on my iPhone 4 to make them work.
Here's the code I'm working with:
$(document).ready(function() {
$('.myMenu > li').bind('mouseover', openSubMenu);
$('.myMenu > li').bind('mouseout', closeSubMenu);
$('.myMenu > li').bind('click', toggleSubMenu);
/* Also tried, currently using:
$('.myMenu > li').bind('tap', toggleSubMenu);
*/
function openSubMenu() {
$(this).find('ul').addClass("hovered");
};
function closeSubMenu() {
$(this).find('ul').removeClass("hovered");
};
function toggleSubMenu() {
$(this).find('ul').toggleClass("hovered").focus();
};
});
The .focus() was the fix I tried adding. It didn't break the code but didn't fix it either. I know there are several things I can do to make it better for touch-devices, but for now, the click method is what I'm sticking with.
By the way:
.hovered{
opacity:1 !important;
visibility: visible !important;
}
The HTML setup is basically <ul>s inside <ul>s like you would expect from a drop-down menu. If you for some reason want the markup just say so and I'll add it.
EDIT: Here's the link to the website I'm working on:
http://bok-it.underbakke.net
EDIT: Some additional information you might find useful that I noticed just now. The first time I click the link, the CSS on that link acts like it's hovered (as : hover) when I click on the sub-link the first time the main link (the one I first clicked to show the dropdown) loses the state of hover. This is why I think this is a focus issue.
EDIT: The HTML markup as requested:
<ul class="myMenu">
<li><span class="icon-home"></span> Framside</li>
<li><span class="icon-cart"></span> Butikk
<ul>
<li><span class="icon-cart"></span> Sand</li>
<li><span class="icon-cart"></span> Sauda</li>
<li><span class="icon-cart"></span> Nettbutikk</li>
</ul>
</li>
<li><span class="icon-console"></span> IT Tjenester
<ul>
<li><span class="icon-console"></span> Driftsavtale</li>
<li><span class="icon-console"></span> ASP & VPS</li>
<li><span class="icon-console"></span> Overvåking</li>
<li><span class="icon-console"></span> Nettverk</li>
</ul>
</li>
<li><span class="icon-info"></span> Support
<ul>
<li><span class="icon-info"></span> Fjernsupport</li>
<li><span class="icon-info"></span> Utskrift ASP</li>
<li><span class="icon-info"></span> RDP: Rycloud</li>
<li><span class="icon-info"></span> TeamViewer Host</li>
</ul>
</li>
<li><span class="icon-mail"></span> Kontakt Oss</li>
</ul>
--------------SOLUTION--------------
EDIT: For people that are seeking the solution to this, here's the jQuery that fixed it for me (You should also give #jonsuh an upvote for wipping out the solution):
$(".myMenu li ul li a").on("touchend", function(event) {
window.location.href = $(this).attr("href");
});
When you mouseover a link in the submenu, the state of the parent list item changes.
However in iOS, when you click on a link in the submenu, it detects that the parent list item state needs to change, so instead of executing a tap, it's changing the state of the item, which is why it's requiring a second tap. (I hope this makes sense).
To cut to the chase, make sure there isn't a state change in the parent list item. Keep it the same when you hover over it as when you're hovering over the submenu links.
I haven't tested these and it's tough when I'm not working with the code live, but possible solutions could be as follows:
You could do it with jQuery and detecting a touch end, which isn't the best solution, but it should work:
$(".myMenu ul li a").on("touchend", function(event) {
window.location.href = $(this).attr("href");
});
Another is to try to keep the state the same with CSS and it may keep Safari from detecting a change in state. (I removed my CSS answer since it didn't work)
Read this: http://sitr.us/2011/07/28/how-mobile-safari-emulates-mouse-events.html
But if a clickable element also does something on mouseover then tapping on that element will trigger a mouseover event instead of a click. Tapping on the same element again will produce a click event.
If you have a mouseover event, iOS (maybe other OSes) will fire that upon initial click rather than the actual click event. I'd add some alerts to your JS to see which event, exactly, is being called on that initial tap.
Instead of having the click event of Jquery try the tap event like
$('.myMenu > li').bind('tap', toggleSubMenu);
Documentation for Tap
I forget where I found this solution but with jQuery I do something like this and it seems to do the trick:
$(document).ready(function() {
$('a,input').bind('touchend', function() {});
});
I used to use 'touchstart' but 'touchend' seems to be working better.
I have small dropdown profile menu with logout button etc. I need to show the menu when I click on the button and hide it when i click anywhere on page or on the button as well.
<div id='menu'>
<ul>
<li class='has-sub'> <a class="testbutton" id="userButton" onclick="dropdown()" href="#">
<span id="buttonText">User name</span> <span id="triangleDown">▾</span>
</a>
<ul id="submenu">
<li class='has-sub'><a href='#'><span>Change password</span></a>
</li>
<li class='has-sub'><a href='logout.php?action=0'><span>Logout</span></a>
</li>
</ul>
</li>
</ul>
</div>
I used JavaScript. At this time menu is displayed on hidded only when I click on profile button. I also know how to start function using something like document.ready.
My not working code:
function dropdown() {
if ($('#submenu').css('visibility') == 'hidden') {
$('#submenu').css('visibility', 'visible');
} else {
$('#submenu').css('visibility', 'hidden');
}
};
$(document).click(function (event) {
if ($('#submenu').css('visibility') == 'visible') {
$('#submenu').css('visibility', 'hidden');
}
});
But when I combine this methods it does not works. So when I clicked on the button to open menu, nothing happened.
Sorry for my English :)
Thanks for help in advance.
This has partly to do with something called event propagation. Put simply, this means that click events will register not only on the clicked element, but also on any parent or ancestor elements of that element.
So if you click a DIV, the event will also be registered on the BODY, because the DIV is inside the BODY. Put abstractly, if a kitchen is the scene of a crime, then the apartment that houses that kitchen is also the scene of a crime. One is inside the other.
This is prevented by preventing propagation - in jQuery, by running the stopPropagation() method of the evt object that is automatically passed to your event handler.
In any case, your situation can be greatly simplified.
var menu = $('#menu'), but = $('#menu_button');
$(document).on('click', '*', function(evt) {
evt.stopPropagation(); //<-- stop the event propagating to ancestral elements
if ($(this).is(but)) //<-- on button click, toggle visibility of menu
menu.toggle();
else if (!$(this).closest(menu).length) //<-- on click outside, hide menu
menu.hide();
});
Assumption: I have assumed that the toggler button is targetable via the selector '#menu_button'. Update this as required. Also, the code should run inside a DOM-ready handler.
The code listens for clicks to any element. If it's registered on the button, the visible state of the menu is toggled. If it's to an element outside of the menu, the menu is hidden. (If, in the latter case, the menu is already hidden, this will have no effect.)
Here's a working JS Fiddle that demonstrates the approach.
Try this:
$(function() {
$('.test-button').click(function(event) {
event.stopPropagation();
$('#submenu').toggle();
});
$('body').click(function() {
var submenu = $('#submenu');
if(submenu.is(":visible")) {
submenu.hide();
}
})
});
EDITED----------------------------------------
With help from users, we have discovered that the load is not working in the javascript. It is only for the topmenu file. Tried the dom ready function and this has not worked. Any further suggestions would be great!
function loadHeader()
{
$("#header").load("http://www.garden-design-courses.co.uk/lib/header.html");
}
function loadTopmenu()
{
$("#topmenu").load("http://www.garden-design-courses.co.uk/lib/topmenu.html");
}
I have a jquery menu that is not showing in IE7 or IE8. Below is the code
http://www.garden-design-courses.co.uk/
$("ul.subnav").parent().append("<span></span>");
$("ul.topnav li span").click(function() { //When trigger is clicked...
//Following events are applied to the subnav itself (moving subnav up and down)
$(this).parent().find("ul.subnav").slideDown('fast').show(); //Drop down the subnav on click
$(this).parent().hover(function() {
}, function(){
$(this).parent().find("ul.subnav").slideUp('slow'); //When the mouse hovers out of the subnav, move it back up
});
//Following events are applied to the trigger (Hover events for the trigger)
}).hover(function() {
$(this).addClass("subhover"); //On hover over, add class "subhover"
}, function(){ //On Hover Out
$(this).removeClass("subhover"); //On hover out, remove class "subhover"
});
The menu is
<ul class="topnav">
<li>Top Navigation
<ul class="subnav">
<li>subnav</li>
</ul>
</li>
</ul>
The problem isn't in that navigation code you have in your question, but in fact because the menu isn't even getting loaded onto the page.
Profiling the code on IE shows that the loadTopmenu function is getting called, but obviously the contents of it aren't getting loaded onto the page.
Try modifying your loadTopmenu to only be called when the DOM is ready:
function loadTopmenu()
{
$(function(){
$("#topmenu").load("http://www.garden-design-courses.co.uk/lib/topmenu.html");
});
}
When I get this behavior it's due to me forgetting to wrap everything up in
$(function(){
...
});
Without it it will work in most browsers except for IE..