Avoid dropdown menu close on click inside - javascript
I have a Twitter Bootstrap dropdown menu. As all Twitter Bootstrap users know, the dropdown menu closes on click (even clicking inside it).
To avoid this, I can easily attach a click event handler on the dropdown menu and simply add the famous event.stopPropagation().
<ul class="nav navbar-nav">
<li class="dropdown mega-dropdown">
<a href="javascript:;" class="dropdown-toggle" data-toggle="dropdown">
<i class="fa fa-list-alt"></i> Menu item 1
<span class="fa fa-chevron-down pull-right"></span>
</a>
<ul class="dropdown-menu mega-dropdown-menu">
<li>
<div id="carousel" class="carousel slide" data-ride="carousel">
<ol class="carousel-indicators">
<li data-slide-to="0" data-target="#carousel"></li>
<li class="active" data-slide-to="1" data-target="#carousel"></li>
</ol>
<div class="carousel-inner">
<div class="item">
<img alt="" class="img-rounded" src="img1.jpg">
</div>
<div class="item active">
<img alt="" class="img-rounded" src="img2.jpg">
</div>
</div>
<a data-slide="prev" role="button" href="#carousel"
class="left carousel-control">
<span class="glyphicon glyphicon-chevron-left"></span>
</a>
<a data-slide="next" role="button" href="#carousel"
class="right carousel-control">
<span class="glyphicon glyphicon-chevron-right"></span>
</a>
</div>
</li>
</ul>
</li>
</ul>
This looks easy and a very common behavior, however, and since carousel-controls (as well as carousel indicators) event handlers are delegated to the document object, the click event on these elements (prev/next controls, ...) will be “ignored”.
$('ul.dropdown-menu.mega-dropdown-menu').on('click', function(event){
// The event won't be propagated up to the document NODE and
// therefore delegated events won't be fired
event.stopPropagation();
});
Relying on Twitter Bootstrap dropdown hide/hidden events is not a solution for the following reasons:
The provided event object for both event handlers does not give reference to the clicked element
I don't have control over the dropdown menu content so adding a flag class or attribute is not possible
This fiddle is the normal behavior and this fiddle is with event.stopPropagation() added.
Update
Thanks to Roman for his answer. I also found an answer that you can find below.
This should help as well
$(document).on('click', 'someyourContainer .dropdown-menu', function (e) {
e.stopPropagation();
});
Removing the data attribute data-toggle="dropdown" and implementing the open/close of the dropdown can be a solution.
First by handling the click on the link to open/close the dropdown like this :
$('li.dropdown.mega-dropdown a').on('click', function (event) {
$(this).parent().toggleClass('open');
});
and then listening the clicks outside of the dropdown to close it like this :
$('body').on('click', function (e) {
if (!$('li.dropdown.mega-dropdown').is(e.target)
&& $('li.dropdown.mega-dropdown').has(e.target).length === 0
&& $('.open').has(e.target).length === 0
) {
$('li.dropdown.mega-dropdown').removeClass('open');
}
});
Here is the demo :
http://jsfiddle.net/RomaLefrancois/hh81rhcm/2/
The absolute best answer is to put a form tag after the class dropdown-menu
so your code is
<ul class="dropdown-menu">
<form>
<li>
<div class="menu-item">bla bla bla</div>
</li>
</form>
</ul>
Bootstrap provides the following function:
| This event is fired immediately when the hide instance method
hide.bs.dropdown | has been called. The toggling anchor element is available as the
| relatedTarget property of the event.
Therefore, implementing this function should be able to disable the dropdown from closing.
$('#myDropdown').on('hide.bs.dropdown', function (e) {
var target = $(e.clickEvent.target);
if(target.hasClass("keepopen") || target.parents(".keepopen").length){
return false; // returning false should stop the dropdown from hiding.
}else{
return true;
}
});
This might help:
$("dropdownmenuname").click(function(e){
e.stopPropagation();
})
I just add onclick event like below to not close dropdown-menu.
<div class="dropdown-menu dropdown-menu-right" onclick="event.stopPropagation()" aria-labelledby="triggerId">
I also found a solution.
Assuming that the Twitter Bootstrap Components related events handlers are delegated to the document object, I loop the attached handlers and check if the current clicked element (or one of its parents) is concerned by a delegated event.
$('ul.dropdown-menu.mega-dropdown-menu').on('click', function(event){
var events = $._data(document, 'events') || {};
events = events.click || [];
for(var i = 0; i < events.length; i++) {
if(events[i].selector) {
//Check if the clicked element matches the event selector
if($(event.target).is(events[i].selector)) {
events[i].handler.call(event.target, event);
}
// Check if any of the clicked element parents matches the
// delegated event selector (Emulating propagation)
$(event.target).parents(events[i].selector).each(function(){
events[i].handler.call(this, event);
});
}
}
event.stopPropagation(); //Always stop propagation
});
Hope it helps any one looking for a similar solution.
Thank you all for your help.
In the new Bootstrap 5 the solution is trivially simple.
Quote from the documentation page:
By default, the dropdown menu is closed when
clicking inside or outside the dropdown menu. You can use the
autoClose option to change this behavior of the dropdown.
In addition to the default behavior, we have 3 options available here:
Clickable outside: data-bs-auto-close="outside"
Clickable inside: data-bs-auto-close="inside"
Manual close: data-bs-auto-close="false"
E.g.:
<div class="btn-group">
<button class="btn btn-secondary dropdown-toggle" data-bs-auto-close="inside" type="button" id="dropdownMenuClickableInside" data-bs-toggle="dropdown" aria-expanded="false">
Clickable inside
</button>
<ul class="dropdown-menu" aria-labelledby="dropdownMenuClickableInside">
<li><a class="dropdown-item" href="#">Menu item</a></li>
<li><a class="dropdown-item" href="#">Menu item</a></li>
<li><a class="dropdown-item" href="#">Menu item</a></li>
</ul>
</div>
More info: https://getbootstrap.com/docs/5.1/components/dropdowns/#auto-close-behavior
$('body').on("click", ".dropdown-menu", function (e) {
$(this).parent().is(".open") && e.stopPropagation();
});
This may work for any conditions.
I tried this simple thing and it worked like a charm.
I changed the dropdown-menu element from <div> to <form> and it worked well.
<div class="nav-item dropdown" >
<a href="javascript:;" class="nav-link dropdown-toggle" data-toggle="dropdown">
Click to open dropdown
</a>
<form class="dropdown-menu ">
<ul class="list-group text-black">
<li class="list-group-item" >
</li>
<li class="list-group-item" >
</li>
</ul>
</form>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"></script>
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" rel="stylesheet"/>
<div class="nav-item dropdown" >
<a href="javascript:;" class="nav-link dropdown-toggle" data-toggle="dropdown">
Click to open dropdown
</a>
<form class="dropdown-menu ">
<ul class="list-group text-black">
<li class="list-group-item" >
List Item 1
</li>
<li class="list-group-item" >
LI 2<input class="form-control" />
</li>
<li class="list-group-item" >
List Item 3
</li>
</ul>
</form>
jQuery:
<script>
$(document).on('click.bs.dropdown.data-api', '.dropdown.keep-inside-clicks-open', function (e) {
e.stopPropagation();
});
</script>
HTML:
<div class="dropdown keep-inside-clicks-open">
<button class="btn btn-primary dropdown-toggle" type="button" data-toggle="dropdown">
Dropdown Example
<span class="caret"></span>
</button>
<ul class="dropdown-menu">
<li>HTML</li>
<li>CSS</li>
<li>JavaScript</li>
</ul>
</div>
Demo:
Generic:
https://jsfiddle.net/kerryjohnson/omefq68b/1/
Your demo with this solution: http://jsfiddle.net/kerryjohnson/80oLdtbf/101/
I modified #Vartan's answer to make it work with Bootstrap 4.3. His solution doesn't work anymore with the latest version as target property always returns dropdown's root div no matter where the click was placed.
Here is the code:
$('.dropdown-keep-open').on('hide.bs.dropdown', function (e) {
if (!e.clickEvent) {
// There is no `clickEvent` property in the `e` object when the `button` (or any other trigger) is clicked.
// What we usually want to happen in such situations is to hide the dropdown so we let it hide.
return true;
}
var target = $(e.clickEvent.target);
return !(target.hasClass('dropdown-keep-open') || target.parents('.dropdown-keep-open').length);
});
<div class="dropdown dropdown-keep-open">
<button class="btn btn-secondary dropdown-toggle" type="button" id="dropdownMenuButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Dropdown button
</button>
<div class="dropdown-menu" aria-labelledby="dropdownMenuButton">
<a class="dropdown-item" href="#">Action</a>
<a class="dropdown-item" href="#">Another action</a>
<a class="dropdown-item" href="#">Something else here</a>
</div>
</div>
$('body').on("click", ".dropdown-menu", function (e) {
$(this).parent().is(".show") && e.stopPropagation();
});
Like for instance Bootstrap 4 Alpha has this Menu Event. Why not use?
// PREVENT INSIDE MEGA DROPDOWN
$('.dropdown-menu').on("click.bs.dropdown", function (e) {
e.stopPropagation();
e.preventDefault();
});
You can also use form tag. Example:
<div class="dropdown-menu">
<form>
Anything inside this wont close the dropdown!
<button class="btn btn-primary" type="button" value="Click me!"/>
</form>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="#">Clik this and the dropdown will be closed</a>
<a class="dropdown-item" href="#">This too</a>
</div>
Source: https://getbootstrap.com/docs/5.0/components/dropdowns/#forms
Bootstrap 5
If anyone comes to this via Google wanting a Bootstrap 5 version like I was, it's built in by adding data-bs-auto-close="outside". Note the option is autoClose but when passing as a data attribute the camelcasing is removed & separated by a dash.
I have a collapse widget in a dropdown & adding data-bs-auto-close="outside" to the parent data-bs-toggle="dropdown" trigger keeps the dropdown open while the collapse is toggled.
See official Bootstrap docs: https://getbootstrap.com/docs/5.1/components/dropdowns/#options
And this codepen for example code (not my pen): https://codepen.io/SitePoint/pen/BaReWGe
I've got a similar problem recently and tried different ways to solve it with removing the data attribute data-toggle="dropdown" and listening click with event.stopPropagation() calling.
The second way looks more preferable. Also Bootstrap developers use this way.
In the source file I found initialization of the dropdown elements:
// APPLY TO STANDARD DROPDOWN ELEMENTS
$(document)
.on('click.bs.dropdown.data-api', clearMenus)
.on('click.bs.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() })
.on('click.bs.dropdown.data-api', toggle, Dropdown.prototype.toggle)
.on('keydown.bs.dropdown.data-api', toggle, Dropdown.prototype.keydown)
.on('keydown.bs.dropdown.data-api', '.dropdown-menu', Dropdown.prototype.keydown)
}(jQuery);
So, this line:
.on('click.bs.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() })
suggests you can put a form element inside the container with class .dropdown to avoid closing the dropdown menu.
Bootstrap has solved this problem themselves in their support for <form> tags in dropdowns. Their solution is quite graspable and you can read it here: https://github.com/twbs/bootstrap/blob/v4-dev/js/src/dropdown.js
It boils down to preventing propagation at the document element and doing so only for events of type 'click.bs.dropdown.data-api' that match the selector '.dropdown .your-custom-class-for-keep-open-on-click-elements'.
Or in code
$(document).on('click.bs.dropdown.data-api', '.dropdown .keep-open-on-click', (event) => {
event.stopPropagation();
});
You could simply execute event.stopPropagation on click event of the links themselves.
Something like this.
$(".dropdown-menu a").click((event) => {
event.stopPropagation()
let url = event.target.href
//Do something with the url or any other logic you wish
})
Edit: If someone saw this answer and is using react, it will not work.
React handle the javascript events differently and by the time your react event handler is being called, the event has already been fired and propagated. To overcome that you should attach the event manually like that
handleMenuClick(event) {
event.stopPropagation()
let menu_item = event.target
//implement your logic here.
}
componentDidMount() {
document.getElementsByClassName("dropdown-menu")[0].addEventListener(
"click", this.handleMenuClick.bind(this), false)
}
}
You can stop click on the dropdown from propagating and then manually reimplement the carousel controls using carousel javascript methods.
$('ul.dropdown-menu.mega-dropdown-menu').on('click', function(event) {
event.stopPropagation();
});
$('a.left').click(function () {
$('#carousel').carousel('prev');
});
$('a.right').click(function () {
$('#carousel').carousel('next');
});
$('ol.carousel-indicators li').click(function (event) {
var index = $(this).data("slide-to");
$('#carousel').carousel(index);
});
Here is the jsfiddle.
demo: http://jsfiddle.net/4y8tLgcp/
$('ul.nav.navbar-nav').on('click.bs.dropdown', function(e){
var $a = $(e.target), is_a = $a.is('.is_a');
if($a.hasClass('dropdown-toggle')){
$('ul.dropdown-menu', this).toggle(!is_a);
$a.toggleClass('is_a', !is_a);
}
}).on('mouseleave', function(){
$('ul.dropdown-menu',this).hide();
$('.is_a', this).removeClass('is_a');
});
i have updated it once again to be the smartest and functional as possible. it now close when you hover outside the nav, remaining open while you are inside it. simply perfect.
I know there already is a previous answer suggesting to use a form but the markup provided is not correct/ideal. Here's the easiest solution, no javascript needed at all and it doesn't break your dropdown. Works with Bootstrap 4.
<form class="dropdown-item">
<!-- Your elements go here -->
</form>
I know this question was specifically for jQuery, but for anyone using AngularJS that has this problem you can create a directive that handles this:
angular.module('app').directive('dropdownPreventClose', function() {
return {
restrict: 'A',
link: function(scope, element, attrs) {
element.on('click', function(e) {
e.stopPropagation(); //prevent the default behavior of closing the dropdown-menu
});
}
};
});
Then just add the attribute dropdown-prevent-close to your element that is triggering the menu to close, and it should prevent it. For me, it was a select element that automatically closed the menu:
<div class="dropdown-menu">
<select dropdown-prevent-close name="myInput" id="myInput" ng-model="myModel">
<option value="">Select Me</option>
</select>
</div>
With Angular2 Bootstrap, you can use nonInput for most scenarios:
<div dropdown autoClose="nonInput">
nonInput - (default) automatically closes the dropdown when any of its elements is clicked — as long as the clicked element is not an input or a textarea.
https://valor-software.com/ng2-bootstrap/#/dropdowns
[Bootstrap 4 Alpha 6][Rails]
For rails developer, e.stopPropagation() will lead to undesirable behavior for link_to with data-method not equal to get since it will by default return all your request as get.
To remedy this problem, I suggest this solution, which is universal
$('.dropdown .dropdown-menu').on('click.bs.dropdown', function() {
return $('.dropdown').one('hide.bs.dropdown', function() {
return false;
});
});
$('.dropdown .dropdown-menu').on('click.bs.dropdown', function() {
return $('.dropdown').one('hide.bs.dropdown', function() {
return false;
});
});
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css" integrity="sha384-rwoIResjU2yc3z8GV/NPeZWAv56rSmLldC3R/AZzGRnGxQQKnKkoFVhFQhNUwEyJ" crossorigin="anonymous">
<script src="https://code.jquery.com/jquery-3.1.1.slim.min.js" integrity="sha384-A7FZj7v+d/sdmMqp/nOQwliLvUsJfDHW+k9Omg/a/EheAdgtzNs3hpfag6Ed950n" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/tether/1.4.0/js/tether.min.js" integrity="sha384-DztdAPBWPRXSA/3eYEEUWrWCy7G5KFbe8fFjk5JAIxUYHKkDx6Qin1DkWx51bBrb" crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/js/bootstrap.min.js" integrity="sha384-vBWWzlZJ8ea9aCX4pEW3rVHjgjt7zpkNpZk+02D9phzyeVkE+jo0ieGizqPLForn" crossorigin="anonymous"></script>
<ul class="nav navbar-nav">
<li class="dropdown mega-dropdown">
<a href="javascript:;" class="dropdown-toggle" data-toggle="dropdown">
<i class="fa fa-list-alt"></i> Menu item 1
<span class="fa fa-chevron-down pull-right"></span>
</a>
<ul class="dropdown-menu mega-dropdown-menu">
<li>
<div id="carousel" class="carousel slide" data-ride="carousel">
<ol class="carousel-indicators">
<li data-slide-to="0" data-target="#carousel"></li>
<li class="active" data-slide-to="1" data-target="#carousel"></li>
</ol>
<div class="carousel-inner">
<div class="item">
<img alt="" class="img-rounded" src="img1.jpg">
</div>
<div class="item active">
<img alt="" class="img-rounded" src="img2.jpg">
</div>
</div>
<a data-slide="prev" role="button" href="#carousel" class="left carousel-control">
<span class="glyphicon glyphicon-chevron-left"></span>
</a>
<a data-slide="next" role="button" href="#carousel" class="right carousel-control">
<span class="glyphicon glyphicon-chevron-right"></span>
</a>
</div>
</li>
</ul>
</li>
</ul>
This helped me,
$('.dropdown-menu').on('click', function (e) {
if ($(this).parent().is(".open")) {
var target = $(e.target);
if (target.hasClass("keepopen") || target.parents(".keepopen").length){
return false;
}else{
return true;
}
}
});
Your drop down menu element needs to be like this, (take a note of the classes dropdown-menu and keepopen.
<ul role="menu" class="dropdown-menu topmenu-menu eserv_top_notifications keepopen">
The above code prevents biding on the whole <body>, instead to the specfic element with the class dropdown-menu.
Hope this helps someone.
Thanks.
The simplest working solution for me is:
adding keep-open class to elements that should not cause dropdown closing
and this piece of code do the rest:
$('.dropdown').on('click', function(e) {
var target = $(e.target);
var dropdown = target.closest('.dropdown');
return !dropdown.hasClass('open') || !target.hasClass('keep-open');
});
I've found none of the solutions worked as I would like using default bootstrap nav.
Here is my solution to this problem:
$(document).on('hide.bs.dropdown', function (e) {
if ($(e.currentTarget.activeElement).hasClass('dropdown-toggle')) {
$(e.relatedTarget).parent().removeClass('open');
return true;
}
return false;
});
Instead of writing some javascript or jquery code(reinventing the wheel). The above scenario can be managed by bootstrap auto-close option.
You can provide either of the values to auto-close:
always - (Default) automatically closes the dropdown when any of its elements is clicked.
outsideClick - closes the dropdown automatically only when the user clicks any element outside the dropdown.
disabled - disables the auto close
Take a look at the following plunkr :
http://plnkr.co/edit/gnU8M2fqlE0GscUQtCWa?p=preview
Set
uib-dropdown auto-close="disabled"
Hope this helps :)
In .dropdown content put the .keep-open class on any label like so:
$('.dropdown').on('click', function (e) {
var target = $(e.target);
var dropdown = target.closest('.dropdown');
if (target.hasClass('keep-open')) {
$(dropdown).addClass('keep-open');
} else {
$(dropdown).removeClass('keep-open');
}
});
$(document).on('hide.bs.dropdown', function (e) {
var target = $(e.target);
if ($(target).is('.keep-open')) {
return false
}
});
The previous cases avoided the events related to the container objects, now the container inherits the class keep-open and check before being closed.
Related
Toggle Bootstrap Chevron
I want to toggle a chevron in a bootstrap drop down menu, when the drop down is toggled. I can make it toggle when clicked, but I would rather it toggle on drop down that way if you click on another part of the menu the chevron changes back. It currently will stay with the minus sign unless you click the chevron to change it back. <li class="dropdown navbar-custom first-navbar-custom"> <a href="#" data-toggle="dropdown" class="dropdown-toggle shortNav hidden-md hidden-lg pull-left cheveron-dropdown"> <span class="chevron_toggleable glyphicon glyphicon-plus glyphiconIcon hidden-md hidden-lg"> </span> </a> <a href="/glass-containers/c/455/"><strong>Glass Containers</strong> </a> <ul class="dropdown-menu"> <script> $(document).ready(function() { $('dropdown-toggle').dropdown('toggle', function() { $('.chevron_toggleable').toggleClass('glyphicon-plus glyphicon-minus'); }); }); </script> I feel like its really close, I just don't have the jquery part correct can someone please help me and tell me what I am doing wrong. The fiddle should explain all. https://jsfiddle.net/nu8wmjq5/
SECOND EDIT BASED ON AUTHORS JSFIDDLE: The code below will react to all events on the dropdowns specific to the class selector. It then finds the chevron that is inside the specific dropdown that has fired the event. FIDDLE: https://jsfiddle.net/t79to9xu/ $(document).ready(function() { $('.myDropdown').on('show.bs.dropdown', function () { $(this).find('.chevron_toggleable') .removeClass("glyphicon-plus") .addClass("glyphicon-minus"); }) $('.myDropdown').on('hide.bs.dropdown', function () { $(this).find('.chevron_toggleable') .removeClass("glyphicon-minus") .addClass("glyphicon-plus"); }) }); I'm sure there is a nicer way of doing this, but I'll let you do your research. .find() searches the descendents of the element. https://api.jquery.com/find/ As such it's worth noting that if your dropdown has two elements with the .chevron-toggleable class inside of it, it'll amend both of them. You'll need to be more specific with your selector if that ever becomes the case. EDIT: I've attached some example code. This is a forked version of the example provided to another question by Skelly here: http://www.bootply.com/zjWn1QPfNU JS: $('#myDropdown').on('show.bs.dropdown', function () { $('#chevron').removeClass("glyphicon-plus").addClass("glyphicon-minus"); }) $('#myDropdown').on('hide.bs.dropdown', function () { $('#chevron').removeClass("glyphicon-minus").addClass("glyphicon-plus"); }) HTML: <div class="btn-group" id="myDropdown"> <a class="btn dropdown-toggle" data-toggle="dropdown" href="#"> Menu <span id="chevron" class="glyphicon glyphicon-plus"></span> </a> <ul class="dropdown-menu"> <li>Choice1</li> <li>Choice2</li> <li>Choice3</li> <li class="divider"></li> <li>Choice..</li> </ul> </div> ORIGINAL ANSWER Bootstrap has a bunch of different events that fire when interacting with a dropdown. They're in the official documentation here. Specifically the ones you'll find of interest are hide.bs.dropdown (event is fired immediately when it is about to be hidden) and hidden.bs.dropdown (fired after the dropdown has been hidden). $('#myDropdown').on('hide.bs.dropdown', function () { // DROPDOWN IS GOING TO CLOSE, CHANGE CHEVRON HERE. })
Does this help? <script> $(document).ready(function() { $('dropdown-toggle').dropdown('toggle', function() { if($('.chevron_toggleable').hasClass('glyphicon-plus')) { $(this).removeClass("glyphicon-plus").addClass("glyphicon-minus"); } else { $(this).removeClass("glyphicon-minus").addClass("glyphicon-plus"); } }); }); </script>
For future researchers this is for navbar dropdowns and this code might help you $(function() { // THIS WILL FIRE WHENEVER DROPDOWN SHOW $('.nav > li.dropdown').on('show.bs.dropdown', function () { $(this).find('.glyphicon').removeClass('glyphicon-chevron-down').addClass('glyphicon-chevron-up'); }); // THIS WILL FIRE WHENEVER DROPDOWN HIDE $('.nav > li.dropdown').on('hide.bs.dropdown', function () { $(this).find('.glyphicon').removeClass('glyphicon-chevron-up').addClass('glyphicon-chevron-down'); }); }); Here is a working fiddle https://jsfiddle.net/qfe9e7tb/1/
Having different click areas on sidenav
I am using bootstrap and in that I am using side nav to serve collapsible list on the left side of the page. Below is my code. <ul class="nav navbar-nav side-nav"> <li> <a class="active" href="#" onclick="loadelementsonpage(); return false" data-toggle="collapse" data-target="#licomp1"> <i class="fa fa-fw fa-arrow-v"></i>Parent1 </a> <ul id="licomp1" class="collapse"> <li>Child1</li> <li>Child2</li> <li>Child3</li> </ul> </li> </ul> Instead of fixed <i class="fa fa-fw fa-arrow-v"></i> I want to use toggle plus and minus. As it is shown in code, I am calling one function when parent1 is clicked. But when I try to expand the ul, the function loadelementsonpage() is called everytime. So, I want list to collapse only when that toggle image is clicked. In the same way I want to call loadelementsonpage() only when the outer area of that toggle image is clicked. I changed this data-toggle and data-target to i class, but the problem is the function is still getting called and if I move the i class out of a tag, the style is messed up. So can someone please shed some light on how to have different click areas on the parent li? One is for collapse and another is for calling function to load right side content page. P.S: Trying to implement this http://cssmenumaker.com/menu/modern-jquery-accordion-menu kind of side nav list where + or - should be clickable for only expanding and collapsing. Please click on build online in that link to see the side nav. Other area(apart from + and - icons) should act as link href to load the page.
Instead of giving the data-toggle attribute to the anchor, give it to the icon element so that toggle works only for the icon. You can use the classes here for plus and minus and toggle between the classes glyphicon-plus and glyphicon-minus <a class="active" href="#"> <span data-toggle="collapse" class="glyphicon glyphicon-plus" data-target="#licomp1"></span>Parent1 </a> $('.side-nav a span').on('click', function () { $(this).toggleClass('glyphicon-plus glyphicon-minus'); }); Now on click of the anchor you can check if the element is A and if true then only call the custom function loadelementsonpage. $('.side-nav a').on('click', function (e) { console.log(e.target.tagName); if (e.target.tagName == "A") { loadelementsonpage(); return true; } }) function loadelementsonpage() { alert('Load elements on page'); } See fiddle
jsbin demo Remove the inline JS you have in your HTML: <a class="active" href="#" data-toggle="collapse" data-target="#licomp1"> <i class="fa fa-fw fa-arrow-v"></i>Parent1 </a> And simply add this to your jQuery: function loadelementsonpage(){ alert("LOADED ELEMENTS! YIIHA"); // Or whatever goes here } $(".side-nav").on("click", "a[data-target]", function(e) { e.preventDefault(); // Prevent default Browser anchor-click behavior if( !$(e.target).hasClass("fa") ){ // If the clicked el. target was not `.fa` // means it was the parent `a` to get the click event. Therefore... e.stopPropagation(); // prevent the click to propagate // to underneath layers triggering stuff and... return loadelementsonpage(); // execute (return) our desired function. } }); (Make sure you have it in document.ready function) What the above does
Proof of concept: function loadelementsonpage(target) { // example stuff $(target).toggle(); } $(".side-nav").on("click", "a[data-toggle]", function(event) { event.preventDefault(); // Prevent default Browser anchor-click behavior var icon = $(event.target).find('.collapseIcon'); if (icon.text() === '+') { icon.text('-'); } else { icon.text('+'); } loadelementsonpage(event.target.getAttribute('data-target')); return false; }); <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <ul class="nav navbar-nav side-nav"> <li> <a class="active" href="#" data-toggle="collapse" data-target="#licomp1"> <span class="collapseIcon">-</span> Parent1 </a> <ul id="licomp1" class="collapse"> <li>Child1 </li> <li>Child2 </li> <li>Child3 </li> </ul> </li> </ul>
jQuery Click Not Being Called in bootstrap navbar
I am having a huge issue with an item in the navbar not being able to use the click() this is my html code: <li class="dropdown"> <a class="dropdown-toggle" id="n-btn" href="#" data-toggle="dropdown"> <i class="icon-bullhorn"></i> <span class="badge badge-inverse" id="n-count" style="position: relative; bottom: 2px;">1</span> </a> <div class="dropdown-menu alert-dropdown"> <ul> <li class="text-center"><span class="pulser"></span></li> </ul> </div> </li> and my javascript: $(window).load(function(){ $("#n-btn").click(function(e) { e.preventDefault(); alert("test"); }); }); I tried using $(".dropdown").on("click", "#n-btn",function() { instead but it still doesn't work. If this changes anything I'm using jquery 2.0.0 and Bootstrap 2.3.2
Looking at the Bootstrap source for 2.3.2 it looks like it triggers the click.dropdown.data-api event, so instead of: $("#n-btn").click(function(e) { use (for Bootstrap 2.x): $("#n-btn").on('click.dropdown.data-api', function(e) { ... For Bootstrap 3.x (looking at its version of dropdown.js), try: $("#n-btn").on('click.bs.dropdown', function(e) { ...
Bootstrap Dropdown with Hover
OK, so what I need is fairly straightforward. I have set up a navbar with some dropdown menus in it (using class="dropdown-toggle" data-toggle="dropdown"), and it works fine. The thing is it works "onClick", while I would prefer if it worked "onHover". Is there any built-in way to do this?
The easiest solution would be in CSS. Add something like... .dropdown:hover .dropdown-menu { display: block; margin-top: 0; /* remove the gap so it doesn't close */ } Working Fiddle
The best way of doing it is to just trigger bootstraps click event with a hover. This way, it should still remain touch device friendly $('.dropdown').hover(function(){ $('.dropdown-toggle', this).trigger('click'); });
You can use jQuery's hover function. You just need to add the class open when the mouse enters and remove the class when the mouse leaves the dropdown. Here's my code: $(function(){ $('.dropdown').hover(function() { $(this).addClass('open'); }, function() { $(this).removeClass('open'); }); });
An easy way, using jQuery, is this: $(document).ready(function(){ $('ul.nav li.dropdown').hover(function() { $(this).find('.dropdown-menu').stop(true, true).delay(200).fadeIn(200); }, function() { $(this).find('.dropdown-menu').stop(true, true).delay(200).fadeOut(200); }); });
For CSS it goes crazy when you also click on it. This is the code that I'm using, it also don't change anything for mobile view. $('.dropdown').mouseenter(function(){ if(!$('.navbar-toggle').is(':visible')) { // disable for mobile view if(!$(this).hasClass('open')) { // Keeps it open when hover it again $('.dropdown-toggle', this).trigger('click'); } } });
In Twitter Bootstrap is not implemented but you can use the this plugin Update 1: Sames question here
Hover over the nav items to see that they activate on hover. http://cameronspear.com/demos/twitter-bootstrap-hover-dropdown/#
So you have this code: <a class="dropdown-toggle" data-toggle="dropdown">Show menu</a> <ul class="dropdown-menu" role="menu"> <li>Link 1</li> <li>Link 2</li> <li>Link 3</li> </ul> Normally it works on click event, and you want it work on hover event. This is very simple, just use this javascript/jquery code: $(document).ready(function () { $('.dropdown-toggle').mouseover(function() { $('.dropdown-menu').show(); }) $('.dropdown-toggle').mouseout(function() { t = setTimeout(function() { $('.dropdown-menu').hide(); }, 100); $('.dropdown-menu').on('mouseenter', function() { $('.dropdown-menu').show(); clearTimeout(t); }).on('mouseleave', function() { $('.dropdown-menu').hide(); }) }) }) This works very well and here is the explanation: we have a button, and a menu. When we hover the button we display the menu, and when we mouseout of the button we hide the menu after 100ms. If you wonder why i use that, is because you need time to drag the cursor from the button over the menu. When you are on the menu, the time is reset and you can stay there as many time as you want. When you exit the menu, we will hide the menu instantly without any timeout. I've used this code in many projects, if you encounter any problem using it, feel free to ask me questions.
This will help you make your own hover class for bootstrap: CSS: /* Hover dropdown */ .hover_drop_down.input-group-btn ul.dropdown-menu{margin-top: 0px;}/*To avoid unwanted close*/ .hover_drop_down.btn-group ul.dropdown-menu{margin-top:2px;}/*To avoid unwanted close*/ .hover_drop_down:hover ul.dropdown-menu{ display: block; } Margins are set to avoid unwanted close and they are optional. HTML: <div class="btn-group hover_drop_down"> <button type="button" class="btn btn-default" data-toggle="dropdown"></button> <ul class="dropdown-menu" role="menu"> ... </ul> </div> Don't forget to remove the button attribute data-toggle="dropdown" if you want to remove onclick open, and this also will work when input is append with dropdown.
This is what I use to make it dropdown on hover with some jQuery $(document).ready(function () { $('.navbar-default .navbar-nav > li.dropdown').hover(function () { $('ul.dropdown-menu', this).stop(true, true).slideDown('fast'); $(this).addClass('open'); }, function () { $('ul.dropdown-menu', this).stop(true, true).slideUp('fast'); $(this).removeClass('open'); }); });
Updated with a proper plugin I have published a proper plugin for the dropdown hover functionality, in which you can even define what happens when clicking on the dropdown-toggle element: https://github.com/istvan-ujjmeszaros/bootstrap-dropdown-hover Why I made it, when there are many solutions already? I had issues with all the previously existing solutions. The simple CSS ones are not using the .open class on the .dropdown, so there will be no feedback on the dropdown toggle element when the dropdown is visible. The js ones are interfering with clicking on .dropdown-toggle, so the dropdown shows up on hover, then hides it when clicking on an opened dropdown, and moving out the mouse will trigger the dropdown to show up again. Some of the js solutions are braking iOS compatibility, some plugins are not working on modern desktop browsers which are supporting the touch events. That's why I made the Bootstrap Dropdown Hover plugin which prevents all these issues by using only the standard Bootstrap javascript API, without any hack.
Try this using hover function with fadein fadeout animations $('ul.nav li.dropdown').hover(function() { $(this).find('.dropdown-menu').stop(true, true).delay(200).fadeIn(500); }, function() { $(this).find('.dropdown-menu').stop(true, true).delay(200).fadeOut(500); });
This only hovers the navbar when you are not on a mobile device, because I find that hovering the navigation does not work well on mobile divices: $( document ).ready(function() { $( 'ul.nav li.dropdown' ).hover(function() { // you could also use this condition: $( window ).width() >= 768 if ($('.navbar-toggle').css('display') === 'none' && false === ('ontouchstart' in document)) { $( '.dropdown-toggle', this ).trigger( 'click' ); } }, function() { if ($('.navbar-toggle').css('display') === 'none' && false === ('ontouchstart' in document)) { $( '.dropdown-toggle', this ).trigger( 'click' ); } }); });
I try other solutions, i'm using bootstrap 3, but dropdown menu closes too quickly to move over it supposed that you add class="dropdown" to li, i added a timeout var hoverTimeout; $('.dropdown').hover(function() { clearTimeout(hoverTimeout); $(this).addClass('open'); }, function() { var $self = $(this); hoverTimeout = setTimeout(function() { $self.removeClass('open'); }, 150); });
Triggering a click event with a hover has a small error. If mouse-in and then a click creates vice-versa effect. It opens when mouse-out and close when mouse-in. A better solution: $('.dropdown').hover(function() { if (!($(this).hasClass('open'))) { $('.dropdown-toggle', this).trigger('click'); } }, function() { if ($(this).hasClass('open')) { $('.dropdown-toggle', this).trigger('click'); } });
Bootstrap drop-down Work on hover, and remain close on click by adding property display:block; in css and removing these attributes data-toggle="dropdown" role="button" from button tag .dropdown:hover .dropdown-menu { display: block; } <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.0/css/bootstrap.min.css"> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.0/js/bootstrap.min.js"></script> </head> <body> <div class="container"> <div class="dropdown"> <button class="btn btn-primary dropdown-toggle">Dropdown Example</button> <span class="caret"></span></button> <ul class="dropdown-menu"> <li>HTML</li> <li>CSS</li> <li>JavaScript</li> </ul> </div> </div> </body> </html>
$('.navbar .dropdown').hover(function() { $(this).find('.dropdown-menu').first().stop(true, true).slideDown(150); }, function() { $(this).find('.dropdown-menu').first().stop(true, true).slideUp(105) });
html <div class="dropdown"> <button class="btn btn-primary dropdown-toggle" type="button" data-toggle="dropdown"> Dropdown Example <span class="caret"></span> </button> <ul class="dropdown-menu"> <li>HTML</li> <li>CSS</li> <li>JavaScript</li> </ul> </div> jquery $(document).ready( function() { /* $(selector).hover( inFunction, outFunction ) */ $('.dropdown').hover( function() { $(this).find('ul').css({ "display": "block", "margin-top": 0 }); }, function() { $(this).find('ul').css({ "display": "none", "margin-top": 0 }); } ); }); codepen
Use the mouseover() function to trigger the click. In this way the previous click event will not harm. User can use both hover and click/touch. It will be mobile friendly. $(".dropdown-toggle").mouseover(function(){ $(this).trigger('click'); })
In Bootstrap 5.x you can add a custom class like dropdown-hover to the main dropdown element. then manage hover events by JQuery. $( document ).ready(function() { // Add hover action for dropdowns let dropdown_hover = $(".dropdown-hover"); dropdown_hover.on('mouseover', function(){ let menu = $(this).find('.dropdown-menu'), toggle = $(this).find('.dropdown-toggle'); menu.addClass('show'); toggle.addClass('show').attr('aria-expanded', true); }); dropdown_hover.on('mouseout', function(){ let menu = $(this).find('.dropdown-menu'), toggle = $(this).find('.dropdown-toggle'); menu.removeClass('show'); toggle.removeClass('show').attr('aria-expanded', false); }); }); <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap#5.2.0/dist/css/bootstrap.min.css"> <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/bootstrap#5.2.0/dist/js/bootstrap.bundle.min.js"></script> </head> <body> <div class="container p-5"> <div class="dropdown dropdown-hover"> <button class="btn btn-secondary dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false"> Dropdown button </button> <ul class="dropdown-menu"> <li> <a class="dropdown-item" href="#">Action</a> </li> <li> <a class="dropdown-item" href="#">Another action</a> </li> <li> <a class="dropdown-item" href="#">Something else here</a> </li> </ul> </div> </div> </body> </html>
The solution I am proposing detects if its not touch device and that the navbar-toggle (hamburger menu) is not visible and makes the parent menu item revealing submenu on hover and and follow its link on click. Also makes tne margin-top 0 because the gap between the navbar and the menu in some browser will not let you hover to the subitems $(function(){ function is_touch_device() { return 'ontouchstart' in window // works on most browsers || navigator.maxTouchPoints; // works on IE10/11 and Surface }; if(!is_touch_device() && $('.navbar-toggle:hidden')){ $('.dropdown-menu', this).css('margin-top',0); $('.dropdown').hover(function(){ $('.dropdown-toggle', this).trigger('click').toggleClass("disabled"); }); } }); <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script> <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/> <ul id="nav" class="nav nav-pills clearfix right" role="tablist"> <li>menuA</li> <li>menuB</li> <li class="dropdown">menuC <ul id="products-menu" class="dropdown-menu clearfix" role="menu"> <li>A</li> <li>B</li> <li>C</li> <li>D</li> </ul> </li> <li>menuD</li> <li>menuE</li> </ul> $(function(){ $("#nav .dropdown").hover( function() { $('#products-menu.dropdown-menu', this).stop( true, true ).fadeIn("fast"); $(this).toggleClass('open'); }, function() { $('#products-menu.dropdown-menu', this).stop( true, true ).fadeOut("fast"); $(this).toggleClass('open'); }); }); <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script> <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/> <ul id="nav" class="nav nav-pills clearfix right" role="tablist"> <li>menuA</li> <li>menuB</li> <li class="dropdown">menuC <ul id="products-menu" class="dropdown-menu clearfix" role="menu"> <li>A</li> <li>B</li> <li>C</li> <li>D</li> </ul> </li> <li>menuD</li> <li>menuE</li> </ul>
You implement this functionality by using Jquery: $('.dropdown').on('mouseover', function(){ $(this).addClass('show'); $('.dropdown-menu').addClass('show'); $('.dropdown-toggle').attr('aria-expanded', 'true'); }); $('.dropdown').on('mouseout', function(){ $(this).removeClass('show'); $('.dropdown-menu').removeClass('show'); $('.dropdown-toggle').attr('aria-expanded', 'false'); });
Tested and Working Fine <nav class="dnt_show_mbl navbar navbar-default navbar-fixed-top" > <div class="container" style="width:100%;"> <div class="navbar-header" style="height:90px;"> <button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#myNavbar"> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> <a class="navbar-brand dnt_show_mbl" href="index.html" style="margin-left:100%;margin-top:2%;"> <img src="material/logo.png" width="160px;" alt="visoka"> </a> <a class="navbar-brand dontdisplaylg" href="index.html" style="" alt="visoka"> <img src="material/logo.png" width="200px;"> </a> </div> <div class="collapse navbar-collapse" id="myNavbar" style="background-color: #fff;border-color:#fff;"> <ul class="nav navbar-nav navbar-right" style="margin-top: 4px;margin-right: 180px;padding:15px;letter-spacing:1px;color:#000;"> <li>HOME</li> <li>ABOUT US</li> <li class="dropdown-header" style="margin-top:-3px;margin-left:-3%;" onmouseout="out_menu();" onmouseover="on_menu();"> <a style="font-family: Inter !important;" class="dropdown-toggle" href="Projects.html">PROJECTS <span class="caret"></span></a> <ul class="dropdown-menu"> <li>Ongoing Projects</li><br> <li>Completed Projects</li><br> <li>Upcoming Projects</li> </ul> </li> </ul> </div> </div> </nav> <script> function on_menu(){ $(".dropdown-header:first").addClass("open"); } function out_menu(){ $(".dropdown-header:first").removeClass("open"); } </script>
Bootstrap 5 with jquery version Just add hoverable class to dropdown and add below code to main javascript file // Hoverable dropdown $('.dropdown.hoverable').on({ mouseenter: function(){ var dropdown = $(this).children('.dropdown-menu'); if(!dropdown.hasClass('show') && dropdown.css('position') !== 'static'){ // Ignore collapsed navbar bootstrap.Dropdown.getOrCreateInstance(this).toggle(); } }, mouseleave: function(){ var dropdown = $(this).children('.dropdown-menu'); if(dropdown.hasClass('show') && dropdown.css('position') !== 'static'){ // Ignore collapsed navbar bootstrap.Dropdown.getOrCreateInstance(this).toggle(); } } });
Prevent the disappear of Dropdown menu using bootstrapDropdown when clicking on the list
I am using using bootstrap-dropdown to generate a Dropdown menu. I would like to prevent the disappearing of the menu when click on it. I have implemented the following code, but it does not work. Any idea how to fix it? HTML <li class="dropdown notification"> <a href="#" class="dropdown-toggle" data-toggle="dropdown"> <span class="notification-label label label-info"> <i class="icon-inbox icon-white"></i> <span class="notification-number">{{ unread_notifications }}</span> </span> </a> <ul class="dropdown-menu notification-list"></ul> </li> JS events: { 'click ul.notification-list': 'onClickNotification' }, onClickNotification: function (e) { e.preventDefault(); console.log(e); },
Did you try with event.stopPropagation? onClickNotification: function (e) { e.stopPropagation(); console.log(e) },
If you want to disable all auto closing of the dropdown you can just disable the listener $('html').off('click.dropdown') JSFiddle