Single dropdown for many items using Twitter Bootstrap - javascript

I have a situation where I have a lot of divs (say each div is a product container, with IDs, titles, image etc).
Inside each div, there is also a button that when clicked I would like to toggle a bootstrap dropdown.
Given the number of items, I dont want each item to have its own markup, so I thought I would create one dropdown and show it programmatically through javascript.
Unfortunately, I cannot find a way. Any help would be appreciated
Thanks in advance
A brief example follows
#jrharshath, thanks for your prompt reply. I post some code (dummy) and I believe that could help you with your answer!
<div id="container">
<div class="acontainer">
<span class="aclicker pull-right btn btn-mini"><i class="icon-chevron-down"></i></span>
<code>ID: w4234234</code><br />
<img src="..." /><br />
product title here
</div>
(many of the above '.acontainer' repeating)
</div><!-- end container -->
<div class="dropdown" id="popmenu">
<ul class="dropdown-menu" role="menu" aria-labelledby="dropdownMenu">
<li><a tabindex="-1" href="#">Action</a></li>
<li><a tabindex="-1" href="#">Another action</a></li>
<li><a tabindex="-1" href="#">Something else here</a></li>
<li class="divider"></li>
<li><a tabindex="-1" href="#">Separated link</a></li>
</ul>
</div>
I want to show the #popmenu whenever someone clicks on any .aclicker elements. Just that.

You could use jQuery to move it around whenever an .aclicker element is clicked.
JavaScript
var $popmenu = $('#popmenu')
, last;
$('body').on('click.dropdown', '.aclicker', function() {
// Make sure it's not already open here
$popmenu.hasClass('open') && last === this ?
$popmenu.removeClass('open') : // close it
// otherwise, reposition
$popmenu
.css({
top: this.offsetTop + this.offsetHeight,
left: this.offsetLeft + this.offsetWidth - 172
})
.children('.dropdown-menu')
.dropdown('toggle'); // then open it
last = this; // save reference
return false;
});​
CSS
#popmenu {
position: absolute;
}
JSFiddle

Related

Bootstrap tab pane will not toggle when using href hash route

Would like to use a basic hash router to drive navigation of bootstrap 4.6 tab component.
However when I call the .tab('show') function, the right tab toggles but it's respective tab-pane section does not get toggled. I made sure the tab-panes id attribute has the same value as the tabs href attribute.
I was able to make it work by manually showing and hiding the tab panes. But bootstrap has this functionality built in. Does anyone know how to do it ?
Thanks
hashRouteInit = function(callback) {
window.addEventListener('hashchange', callback, false);
}
const routes = {
'#/units': function() {
console.log('units');
},
'#/clients': function() {
console.log('clients');
},
'#/searches': function() {
console.log('searches');
},
};
hashRouteInit(function() {
console.log(window.location.hash);
console.log(routes);
if (routes[window.location.hash] != undefined) {
/*how can i remove the following 3 lines and let .tab('show') show the tab pane*/
/*$(`.tab-content .show`).hide();
$(`.tab-content .show`).removeClass('show');
$(`.tab-content .show`).removeClass('active');*/
$(`#stats-tabs a[href="${window.location.hash}"]`).tab('show');
/*how can i remove the following 3 lines and let .tab('show') show the tab pane*/
/*$(`.tab-content .tab-pane[id="${window.location.hash}"]`).addClass('show');
$(`.tab-content .tab-pane[id="${window.location.hash}"]`).addClass('active');
$(`.tab-content .tab-pane[id="${window.location.hash}"]`).show();*/
routes[window.location.hash]();
}
});
<head>
<link href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/4.6.0/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div id="container">
<ul class="nav nav-tabs" id="stats-tabs" role="tablist">
<li class="nav-item" role="presentation"><a class="nav-link active" id="units-tab" href="#/units" role="tab" aria-controls="units" aria-selected="true">Units</a></li>
<li class="nav-item" role="presentation"><a class="nav-link" id="clients-tab" href="#/clients" role="tab" aria-controls="clients" aria-selected="false">Clients</a></li>
<li class="nav-item" role="presentation"><a class="nav-link" id="searches-tab" href="#/searches" role="tab" aria-controls="searches" aria-selected="false">Searches</a></li>
</ul>
<div class="tab-content pt-2" id="stats-tabs-content">
<div class="tab-pane fade show active" id="#/units" role="tabpanel" aria-labelledby="units-tab">units</div>
<div class="tab-pane fade" id="#/clients" role="tabpanel" aria-labelledby="clients-tab">clients</div>
<div class="tab-pane fade" id="#/searches" role="tabpanel" aria-labelledby="searches-tab">
<div id="search-overview-searches">searches</div>
</div>
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/4.6.0/js/bootstrap.min.js"></script>
</body>
Apparently the HTML ID attribute has to start with a letter(https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/id)
Once I set the href attributes to #name and used the same value but without the number sign for the ID of the tab pane. It started working.
Note that the spec(https://www.w3.org/TR/2011/WD-html5-20110525/elements.html#:~:text=The%20id%20attribute%20specifies%20its,not%20contain%20any%20space%20characters.) doesn't say anything about not using slashes to construct a hierarchy in the id string. However if i want to have another tab section as a child in a tab pane, i won't be able to have an id like this(parent/child) and have bootstrap tabs work. So you are only left with - or _ which doesn't seem so intuitive in the URI. Especially once you wan't to add an numerical identifier onto it. Like so parent/child/3. Can't do that, but the spec doesn't say anything about not allowing slashes.
Does anyone know why forward slashes are not allowed in the id string if the first char is not a forward slash?

Automatically toggle html tabs

I have the following tab structure in the form of a form with a submit button on the second tab. Is it possible for the tabs to auto-change upon a certain condition?
<ul class="nav nav-tabs">
<li class="active"><a data-toggle="tab" href="#home">Home</a></li>
<li><a data-toggle="tab" href="#menu1">Menu 1</a></li>
<li><a data-toggle="tab" href="#menu2">Menu 2</a></li>
</ul>
<div class="tab-content">
<div id="home" class="tab-pane fade in active">
<h3>HOME</h3>
<p>Some content.</p>
</div>
<div id="menu1" class="tab-pane fade">
<h3>Menu 1</h3>
<p>Some content in menu 1.</p>
</div>
<div id="menu2" class="tab-pane fade">
<h3>Menu 2</h3>
<p>Some content in menu 2.</p>
</div>
</div>
It's pretty hard to answer this without knowing what condition you want or seeing any code apart from the HTML structure (and without any CSS).
I'm assuming clicking on the anchors will change tabs, so what you need to do is add ids to them:
<li><a data-toggle="tab" href="#menu1" id="tab1">Menu 1</a></li>
<li><a data-toggle="tab" href="#menu2" id="tab2">Menu 2</a></li>
and then if you're using jQuery do something like:
if(/*whatever condition you want*/){
$('#tab2').click();
}
otherwise:
if(/*whatever condition you want*/){
document.getElementById('tab2').click();
}
What you're looking for is called a multi-step form or a form wizard.
There are multiple examples on google on how to achieve such a solution and many many many JavaScript and jQuery modules/libraries which provide such functionality.
one sample can be found at this JSFiddle by JQ Purfect using bootstrap wizard:
http://jsfiddle.net/JQPurfect/nGnbJ/2/
$(document).ready(function () {
$('#rootwizard').bootstrapWizard({
onTabShow: function (tab, navigation, index) {
var $total = navigation.find('li').length;
var $current = index + 1;
var $percent = ($current / $total) * 100;
$('.bar').text($percent.toFixed(0) + '%');
$('#rootwizard').find('.bar').css({
width: $percent + '%'
});
}
});
window.prettyPrint && prettyPrint()
});
Or follow this one: https://www.npmjs.com/package/jquery-simple-wizard
You can use the bootstrap tabs javascript reference to manipulate tabs to do something based on a condition. You can see the javascript reference at http://www.w3schools.com/bootstrap/bootstrap_ref_js_tab.asp. If you are trying to show your tab then you should be able to just use something like the following:
$('.nav-tabs a[href="#menu2"]').tab('show')
Not knowing what condition you want to toggle the tab on I made a fiddle to show you with just a click function but you can use whatever fucntion you want to show the tab.
Here is a fiddle Fiddle

How to hide one item in boostrap dropdown

This is my bootstrap code.
<label>Select Leave Type</label>
<div class="dropdown">
<i class="dropdown-arrow dropdown-arrow-inverse"></i>
<button class="btn btn4 btn-default dropdown-toggle" type="button" id="menu0" data-toggle="dropdown">--Select--
<span class="caret"></span></button>
<ul class="dropdown-menu dropdown-inverse0" role="menu" aria-labelledby="menu0" id="drp0">
<li role="presentation"><a data-myAttribute0="casual" class="list0" href="#" >Casual Leave</a></li>
<li role="presentation"><a data-myAttribute0="annual" class="list0" href="#" >Annual Leave</a></li>
<li role="presentation"><a data-myAttribute0="medical" class="list0" href="#" >Medical Leave</a></li>
</ul>
</div>
This is the code I usually use to hide whole dropdown.
$('.btn4').css('visibility', 'hidden');
But at the moment I want to hide one item. Can't figure-out that. Please help me. Thank you.
EDIT 1
When I use
<script>
$('document').ready(function () {
$('#drp0 li').eq(1).css('visibility', 'hidden');
});</script>
This happens.
As you can understand this is not what I need.Please give me more suggestion
To use absolutely Bootstrap solution you can add hide class to the element you want to hide.
For example:
<li role="presentation"><a data-myAttribute0="annual" class="list0 hide" href="#" >Annual Leave</a></li>
Here's example on BootPly: http://www.bootply.com/q7gTTiFzOT
If you want this to be done dynamically using jQuery you can try this:
$('ul > li:eq(1)').addClass('hide');
1
$("li:eq(1)").css('visibility', 'hidden');
2 or you can give every "li" a id,and then
$("#id").css('visibility', 'hidden');
// hide first item
$(".btn4").click(function(){
$('.dropdown-menu li').eq(0).css('visibility', 'hidden');
});
Select the li elements inside drp0 (which is the id of your dropdown menu) then choose which element to hide from the list that is returned (starting at zero for the first item) like this:
// hide first item
$('#drp0 li').eq(0).css('visibility', 'hidden');
// hide second item
$('#drp0 li').eq(1).css('visibility', 'hidden');
// hide third item
$('#drp0 li').eq(2).css('visibility', 'hidden');
// etc
From the jQuery docs:
.eq( index )
Description: Reduce the set of matched elements to the one at the specified index.
https://api.jquery.com/eq/
You might want to use display:none; to collapse the element:
// hide second item
$('#drp0 li').eq(1).css('display', 'none');

Avoid dropdown menu close on click inside

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.

jQuery - Disable list of links and move active link down the list in sequence

I'm trying to test the effectiveness of a navigational function in my prototype. On the left side of the page, I have an unordered list with 30 list items that flows off of the page. On the right side of the page is a prompt that is asking users to click through the navigational items in a randomized sequence.
The right and left side are displayed inside of iFrames, with the clicks on the left navigation updating the content on the right and in turn prompting users to click on the next item in the sequence. I'd like to avoid having all 30 list items live at once, to avoid test users erroneously clicking any item other than the next item in the sequence. Is it possible, using jQuery (or anything else, for that matter), to have the HREF in the navigation track the order of my sequence and link each item when it appears in the sequence and be unlinked when it does not appear next in the sequence?
Thanks.
EDIT:
I've made a bit of headway here. My javascript is still not producing the desired result (disable all links except for the current link in the sequence, and once click, disable the link and activate the next one in the sequence). I've simplified the scope of the list to make the problem easier to handle for now.
var linkInterceptor = function(event) {
if($(event.target).hasClass("active")) {
$('a').removeClass("active");
// assume links have class="nextlink_##"
var nextTarget = $(event.target).getAttr('class');
var nextId = nextTarget.substr(9);
$('#' + nextId).addClass("active");
return true;
} else {
event.preventDefault();
}
};
$('a').on('click', linkInterceptor);
And here is the HTML
<div style="width:1024px; height:768px;">
<div style="width:298px; height:708px; overflow:scroll; float:left;">
<a class="nextlink_2" id="1" target="frame2" href="instruction_2.html">img</a>
<a class="nextlink_3" id="2" target="frame2" href="instruction_3.html">img</a>
<a class="nextlink_4" id="3" target="frame2" href="instruction_4.html">img</a>
<a class="nextlink_5" id="4" target="frame2" href="instruction_5.html">img</a>
<a id="5" target="frame2" href="instruction_6.html">img</a>
</div>
<div style="width:726px; float:left;">
<iframe src="instruction_1.html" width="726" height="100%" scrolling="auto" frameborder="0" id="frame2"></iframe>
</div>
</div>
Any idea where I'm going astray?
Figured it out. Below is the code to deactivate the links in the list, step through a pre-determined, unordered sequence based on link ID and, on click, deactivate a link and activate the next in the sequence. The javascript:
<script>
var linkInterceptor = function(event) {
if($(event.target).hasClass("active")) {
$('a').removeClass("active");
// assume links have class="nextlink_##"
var nextTarget = $(event.target).attr('class');
var nextId = nextTarget.substr(9);
$('#' + nextId).addClass("active");
return true;
} else {
event.preventDefault();
}
};
$('a').on('click', linkInterceptor);
</script>
And a sample of the final HTML:
<div style="width:1024px; height:768px;">
<div style="width:298px; height:708px; overflow-y: scroll; overflow-x:hidden; float:left; padding-bottom:-20px; margin-bottom:-20px;">
<li><a class="nextlink_13" id="12" target="frame2" href="instruction_13.html">Name 1</a></li>
<li><a class="nextlink_11" id="10" target="frame2" href="instruction_11.html">Name 2</a></li>
<li><a class="nextlink_20" id="19" target="frame2" href="instruction_20.html">Name 3</a></li>
<li><a class="nextlink_3" id="2" target="frame2" href="instruction_3.html">Name 4</a></li>
<li><a class="nextlink_16" id="15" target="frame2" href="instruction_16.html">Name 5</a></li>
</div>
</div>
The list is 30 names long so I've truncated it above. To achieve the planned randomness, I just numbered the IDs based on the order we preferred.
I have created a small JSFiddle that works. http://jsfiddle.net/79ZFR/
Essentially I remove the current click handler and then add a click handler to the next number.
function AddClick(number) {
$("#" + number).click(function () {
$("#" + number).off('click');
AddClick(number+1);
});
}​
Then all you need to do is to initialize it on load.
$(function () {
AddClick(1);
});
My HTML is:
<ul>
<li><a id="1" href="#">1</a></li>
<li><a id="2" href="#">2</a></li>
<li><a id="3" href="#">3</a></li>
<li><a id="4" href="#">4</a></li>
<li><a id="5" href="#">5</a></li>
</ul>
but if you want it randomized then you can easily do that in the back end.
I didn't use any iframes in this.
NOTE: For your final one you'll need to handle your stop timer event.
EDIT:
For a randomized list I would do it on the back end and generate my HTML like
<ul>
<li><a id="5" href="#">5</a></li>
<li><a id="3" href="#">3</a></li>
<li><a id="1" href="#">1</a></li>
<li><a id="4" href="#">4</a></li>
<li><a id="2" href="#">2</a></li>
</ul>

Categories