I am trying to create a dropdown javascript menu with jquery. I am using hide() and show(). I made it so that when you click on a menu item it shows but I cannot figure out how to make it so that when you click on anything other than the menu it will hide. I have seen it done on multiple sites before. How do you do it?
The gist of it:
// variable menu is your jquery menu ref.
var outsideMenu= function(){
menu.hide();
// clean up listener
$(document).unbind('click', outsideMenu);
}
$(menu).mouseout(function(){
// cursor is off the menu so attach listener
$(document).click(outsideMenu);
}).mouseover(function(){
// back to menu, so remove listener
$(document).unbind('click', outsideMenu);
});
I assume you can take it from there ;)
This may be what you're looking for.
Related
I'm trying to make a function that will be fired with the 'onclick' event of a procedurally added div.hb-menu-subMenuToggle element. The function works when using the initial selector as anything but '$(this)'
// FUNCTION: hbMenuSubToggle()
// Toggles CSS classes for animation of .hb-menu-sub-open. Fires when clicking the div element with .hb-menu-subMenuToggle class
function hbMenuSubToggle(){
// TESTING: This works as far as opening the submenus; however, it does not open only the submenu that is a direct sibling of the hb-menu-subMenuToggle element.
$('a.withSubmenu').siblings('ul').toggleClass('hb-menu-sub-open');
// DESIRED EFFECT: Does not work
$(this).siblings('ul').toggleClass('hb-menu-sub-open');
};
Here's a link to the
Codepen Project
Any help would be greatly appreciated!
The correct way to do this would be to use jQuery event handlers rather than using onClick and a function inline in your HTML.
For example if you place this within your $(document).ready() it will attach a click event handler to all A elements in your top menu. When it is clicked you will be able to get $(this) (which is the A element) and then traverse to its parent (the UL element) and then find the child UL elements (the sub menu) to toggle the class.
$('#main-nav>ul>li').on('click', '>a', function(){
$(this).parent().find('ul').toggleClass('hb-menu-sub-open');
});
Similarly your function to show the main menu could also be written as follows
$(document).on('click', '.hb-menu-btn', function(){
$('.hb-menu-btn, .hb-menu, .hb-menu-page').toggleClass('hb-menu-open');
});
See it working on CodePen here: http://codepen.io/anon/pen/rOKQOJ
function hbMenuSubToggle(divyouneed){
// TESTING: This works as far as opening the submenus; however, it does not open only the submenu that is a direct sibling of the hb-menu-subMenuToggle element.
$('a.withSubmenu').siblings('ul').toggleClass('hb-menu-sub-open');
// DESIRED EFFECT: Does not work
divyouneed.siblings('ul').toggleClass('hb-menu-sub-open');
};
and use it
hbMenuSubToggle($(this))
for $(this) you have to had selected one element before. In a function you dont have it like that.. So it will only work if you select it directly and not with $(this)
function hbMenuSubToggle() {
$('.blablabla').blablabla();
}
And read this to find out more about jQuerys basics
I'm trying to create a top-nav menu as follows:
The idea is that when you click a tab, the tab itself gets highlighted in black and an associated menu shows up beneath it. This works fine.
I also want the menu to disappear and the tab to be unhighlighted if the mouse leaves either the tab or the menu. This is where I'm running into trouble. At the moment, the JQuery I use to handle this is roughly as follows:
$('.item-support a').click(function(e){
// removeClass('curr') from all other tabs
$('.item-support').addClass('curr');
$('#submenu-support').fadeIn('fast');
$('.item-support').mouseleave(function(e) {
$('.item-support').removeClass('curr');
$('#submenu-products').fadeOut('fast');
});
}else{ // Click again
$('.item-support').removeClass('curr');
$('#submenu-support').fadeOut('fast');
}
return false;
});
$('#submenu-products').mouseleave(function(e) {
$('.item-support').removeClass('curr');
$('#submenu-products').fadeOut('fast');
});
// Similar code for the other tabs
The problem is that the mouseleave events for the tab and sub-menu are not synchronized. So, for example, if the mouse leaves the support tab and enters the submenu below it, the submenu vanishes. I've tried many different approaches to get around this and even have one that crudely works using pageX and pageY co-ordinates, but I'm looking for a more elegant solution. How do I get the tab and its associated submenu to work in tandem? Is there a way to bind the two divs together? Or make mouseleave recognize an exception when entering a certain div?
You can check if either element is hovered, and do something like this:
$('.item-support, #submenu-support').mouseleave(function() {
setTimeout(function() {
if (!$('.item-support').is(':hover') && !$('#submenu-support').is(':hover')) {
$('.item-support').removeClass('curr');
$('#submenu-support').hide();
}
}, 50);
});
You also shouldn't bind your mouseleave event in the callback of another event. Currently every time you click item-support, you are binding another mouseleave event to it.
I am using Bootstrap dropdown menu. See the below code:
$(document).ready(function(){
$("#a-primary-occasion").mouseover(function(){
$(".dropdown-menu_occasion").css("display", "block");
});
$('#submenu-birthday_occasion').mouseover();
});
This script is in main menu's phtml file which works fine when the page is loaded. But after clicking outside menu (on other content of the page.) it doesn't fire the mouseover() event.
You can check it here: http://jshri.com
After loading the page just hover on the first menu (Occasion). It will open the submenu of "Birthday Gifts".
click on anywhere outside the menu (e.g above "Occasion" menu)
hover on Occasion menu it won't open the first menu. Also hovering on the first submenu (i.e. Birthday Gifts) won't it. But after hovering on the second submenu (i.e. Anniversary Gifts) will open the submenu also the hover even for the first submenu will work fine afterwards.
Note: If I add an alert in document.ready() it fires every time.
I am not sure why is this happening. Does anyone have any idea? How can I solve this?
I found it myself!
As I said I am using Bootstrap menu, by default menu was opening on click events. Which I changed to hover event. But I didn't remove the jQuery which was hiding the current opened menu on document.click event. This is the code I commented:
$(document).click(function() {
// Simply hide the submenu on any click. Again, this is just a hacked
// together menu/submenu structure to show the use of jQuery-menu-aim.
$(".popover_relation").css("display", "none");
$("a.maintainHover_relation").removeClass("maintainHover_relation");
});
I've recently started using Twitter's new Bootstrap 2.0.1 and its Javascript popovers.
I want to write a script so that no more than one popover can be displayed at one time. In other words, when a new popover is generated for whatever reason (e.g. the client clicks or hovers over a new element with a popover), all of the PREVIOUSLY displayed popovers are hidden first.
Here's the function that initially sets up all of the popovers for my webpage:
$(function (){
$("[rel=popover]").popover({placement:'left', trigger:'click', html:true});
});
What I need, I think, is to write a function that hides all popovers. I would call that function BEFORE displaying every popover, to ensure that only one popover is displayed at a time. The function might look like this, I imagine:
function hidePopovers(){
$(function (){
$("[rel=popover]").popover('hide');
});
}
But my problem is figuring out WHERE (or HOW) to call this hidePopovers function. I want to call it when a popover is triggered, but before the popover is displayed. Help?
Oh, and just to clear up any confusion, the new Bootstrap now has a 'click' trigger that allows you to display popovers upon clicking. More details about it can be found here.
Thank you so much!
Considering what you have presented as the problem to solve, I think that it would be much more efficient to simply store a reference to the last popover open, rather than execute the hide() method on every single popover element you might select on the page. As far as I understand it, you only want a single popover to be open in the first place, so there should only ever be at most a single one to hide.
The following would do the trick:
var $visiblePopover;
$('body').on('click', '[rel="popover"]', function() {
var $this = $(this);
// check if the one clicked is now shown
if ($this.data('popover').tip().hasClass('in')) {
// if another was showing, hide it
$visiblePopover && $visiblePopover.popover('hide');
// then store reference to current popover
$visiblePopover = $this;
} else { // if it was hidden, then nothing must be showing
$visiblePopover = '';
}
});
JSFiddle
Technically, you could potentially change the selector where the delegate handler is attached (in the example code 'body' is used) to a more specific element of the page, allowing you to attach the only-one-visible-at-a-time behavior to only a subset of the popovers on the page.
For instance, if you had a specific form where the popovers would appear too close together, but other popups on the page wouldn't collide/overlap, you could select just the form (e.g., '#some_form_id'), and only the popups in the form would have the behavior.
JSFiddle
Note: In this latter example, I also optimized the code a bit by changing the stored reference to only use the actual Popover object, rather than the jQuery-ized DOM element it is attached to.
Haven't tested this but something like this might work:
Set the trigger to manual.
Listen for click events and on click, call hidePopovers(), and then show the clicked popover.
$(function (){
function hidePopovers(){
$(function (){
$("[rel=popover]").popover('hide');
});
}
$("[rel=popover]").popover({placement:'left', trigger:'manual', html:true});
$("[rel=popover]").click(function() { hidePopovers(); $(this).popover('show');});
});
The title is a little bit messy, so let me try to explain in the actual question:
Suppose I have the following HTML setup.
<div id="userMenu">
<div id="userMenu-expanderLink">Mouseover here!</div>
<div id="userMenu-collapserLink">You can close the menu by mouse out.</div>
<div id="userMenu-expandedContent">Extra Content</div>
</div>
Now, userMenu and userMenu-expanderLink are shown by default. userMenu-expandedContent and userMenu-collapserLink are hidden by default.
What I am trying to do in jQuery is to slideDown the userMenu-expandedContentwhen a mouseover event occurs on userMenu-expander. All good there, this is my code:
$("#userMenu-expanderLink").mouseover(function() {
$("#userMenu-expandedContent").stop().slideDown(200);
$("#userMenu-expanderLink").hide();
$("#userMenu-collapserLink").show();
$("#userMenu").addClass("userMenu-expanded");
});
As you can see, I'm also hiding the expanderLink and showing the collapserLink; and also adding a class called userMenu-expanded to #userMenu. Until now, this code has no problems. Everything works well.
But now, I want that when the user has a mouseOut event on #userMenu.userMenu-expanded, effectively moving his mouse out of the #userMenu that is expanded, I want when that happens, the expandedContent is slideUp'd, the expander and collapser links swapped, and the class removed. I know how to do that, but handling the event seems to be a problem.
Putting $("#userMenu.userMenu-expanded")... directly alongside the code I have of course does not work, since a div with such id and such class is only generated if the menu has been expanded, and the div's class is removed once the menu is collapsed. I don't directly use a mouseover/mouseout event on one object because I want the collapsing to be triggered only when the user takes his mouse out of the menu, not the expander link.
So, here's my problem. How can I get such mouse out event? I have tried adding the event handler in the callback of .addClass, but no avail, it would basically permanently close that expanded menu (basically I can't ever expand it again until I reload the page).
How can this be done? I'm not very experienced with jQuery, so a detailed answer would be most appreciated. I'm more interested on how can this be done rather than just accomplishing it, I want to learn ^_^.
Thanks!
I have found a correct way to do this. This is my final implementation.
$(document).ready(function() {
// UserMenu Expander, which is also a form of drop down
$("#userMenu-expander").mouseenter(function() {
//alert("Usermenu expanding…");
$("#userMenu-expandedContent").slideDown(200, function() {
$("#userMenu").addClass("userMenu-expanded");
});
$("#userMenu-expanderLink").hide();
$("#userMenu-collapserLink").show();
});
$("#userMenu.userMenu-expanded").live('mouseleave', function() {
//alert("Usermenu de-expanding…");
$("#userMenu-expandedContent").slideUp(200);
$("#userMenu-expanderLink").show();
$("#userMenu-collapserLink").hide();
$("#userMenu").removeClass("userMenu-expanded");
});
});