On click stopPropagation while keeping bootstrap collapse behavior - javascript

I have a bootstrap list-group-item with a badge as follows:
<a class="list-group-item list-group-item-action" href="#" revision="211147" id="commit0">
<span class="badge collapsed" id="badge0" data-toggle="collapse" data-target="#ul0" >
changed files:1
</span>
<ul class="list-group changed-files-list collapse" id="ul0" aria-expanded="false" style="height: 0px;">
<li class="list-group-item changed-file">
release.groovy
</li>
</ul>
</a>
It contains a collapsed ul that is targeted by the badge.
At the same time, when clicked, the a element is selected(as it is part of a list-group with multiple selection possible).
I try to insert this bit of code:
$('.badge').on('click', function(e){
//$('#'+this.id).click();
e.stopPropagation();
});
so that when clicking on the badge the a element is not selected.
If I use this code the ul element is not being shown. I guess bootstrap uses the on click function and so it has something to do with my function overriding the bootstrap one.
How can I stop propagation while keeping the collapse behavior?

I found the solution by using bootstrap's collapse function:
$('.badge').click( function(e){
$('#ul'+this.id.substring(5)).collapse("toggle");
e.stopPropagation();
});

Related

How to close Hamburger menu when clicked outside the menu using Javascript

I have been working some code, where I use Hamburger responsive menu. The menu opens and closes when clicked on the hamburger icon. I wanted to add a functionality for closing the menu when clicked outside the menu. I managed to close the menu when clicked outside but without the close animation.
Here is the JS code that I tried:
$(document).on("click", function () {
$(".navbar-collapse").removeClass("show");
});
and the HTML code:
<nav class="navbar navbar-expand-lg tm-navbar" id="tmNav">
<div class="container">
<button
class="navbar-toggler"
type="button"
data-toggle="collapse"
data-target="#navbarSupportedContent"
aria-controls="navbarSupportedContent"
aria-expanded="false"
aria-label="Toggle navigation"
>
<i class="fas fa-bars navbar-toggler-icon"></i>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav mr-auto">
<li class="nav-item">
A
</li>
<li class="nav-item">
B
</li>
<li class="nav-item">
C
</li>
<li class="nav-item">
D
</li>
</ul>
</div>
The above JS code closes the menu when clicked outside the menu but without the animations. I would like to close the menu with the closing animation. Would appreciate some help with this issue.
If this is Bootstrap's Collapse component (which it looks like considering the collapse and navbar-collapse classes), you don't want to remove the show class yourself. As you found out, that will skip all the other work Bootstrap does; including animating the transition.
Instead, use the provided .collapse('hide') event to cause Bootstrap to close the Collapse for you.
$(document).on('click', function () {
$('#navbarSupportedContent').collapse('hide');
});

How to use a JQuery Selector to find a DOM Element based on one of its multiple classes

My direct/exact question can be found at the very bottom. The following is a bit of background info/ explanation.
So I've got this jQuery function written up in TS
startEventListeners = () => {
$(document).ready(() => {
$('.dropdown-submenu a.test').on('click', function (e) {
$(this).next('ul').toggle();
e.stopPropagation();
e.preventDefault();
});
});
};
And it's purpose is to open up sub-menu items in a drop down list, and that looks like this
<div class="container">
<div class="dropdown">
<button class="btn btn-default dropdown-toggle" type="button" data-toggle="dropdown">
New
<span class="caret"></span>
</button>
<ul class="dropdown-menu">
<li class="dropdown-submenu">
<a class="test" tabindex="-1" href="#">Blank Template <span class="caret"></span></a>
<ul class="dropdown-menu">
<li>As Library Template</li>
<li>For This Use Only</li>
</ul>
</li>
<li class="dropdown-submenu">
<a class="test" tabindex="-1" href="#">Copy of... <span class="caret"></span></a>
<ul class="dropdown-menu">
<li class="dropdown-submenu" ng-repeat="options in $ctrl.templateLookup.data">
<a class="test" href="#">{{options.key}} <span class="caret"></span></a>
<ul class="dropdown-menu">
<li>As Library Template</li>
<li>For This Use Only</li>
</ul>
</li>
</ul>
</li>
</ul>
</div>
</div>
And it's going well up until I get to these two lines
<li class="dropdown-submenu" ng-repeat="options in $ctrl.templateLookup.data">
<a class="test" href="#">{{options.key}} <span class="caret"></span></a>
My jquery selector is looking specifically for the classes, "dropdown-menu" and "test"
Because I'm using angular which is doing its job, no problems there; some classes are getting injected into those two lines and turning them into this
<li class="dropdown-submenu ng-scope" ng-repeat="options in $ctrl.templateLookup.data">
<a class="test ng-binding" href="#">{{options.key}} <span class="caret"></span></a>
So now my jquery selector can't find them. And I would just change the selector to search for .dropdown-submenu.ng-scope, and .test.ng-binding, but there's two other locations that use dropdown-submenu, and test, but don't use any angular so then my selector wouldn't find them.
After that mouthful of background info (sorry) my question is this.
Is there a way to format my jquery selector to find the DOM element I need it to find not based on its complete class, i.e. .dropdown-submenu.ng-scope, but off of just one of its multiple classes?
Perhaps try something like this
$('document').on('click','.dropdown-submenu, a.test',function( e ){ })
This should register ANY click events and validate it against the selectors at the time of the event rather than watching for a pre build list that may not yet exist.
After you do this you could have the regular e.stopPropagation(); and e.preventDefault(); in the function and just take action using $( this ) that way you can single out the dom element that you clicked on.
in my opinion, your problem relates to http://api.jquery.com/on/#direct-and-delegated-events
try changing your code to the following:
startEventListeners = () => {
$(document).ready(() => {
$(document).on('click', '.dropdown-submenu a.test', function (e) {
$(this).next('ul').toggle();
e.stopPropagation();
e.preventDefault();
});
});
};
this will allow those repeated elements (created by Angular after your $(document).ready have been executed) to get the delegated click event too
PS: the change is only for the click line

href links not opening, bootstrap add open class to dropdown menu when click instead of opening link

Any ideas how to fix? This applies to the "Animations" and "Education" links. Click these should open a new page, but bootstrap.min just adds the .open class.
HTML
<li class="dropdown cases videos">
<a class="dropdown-toggle" href="videos.html" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false" id="main-nav">Animations</a>
<ul class="dropdown-menu cases-body videos-drop">
<p style="padding-top:15px;" class="category-cases">Building a Park Out of Waste</p>
<p class="category-cases">Designing for Active Living</li>
<p class="category-cases">Designing Neighborhoods for People and Wildlife</p>
<p class="category-cases">The Edible City</li>
<p class="category-cases">Energy Efficient Home Landscapes</p>
<p class="category-cases">From Industrial Wasteland to Community Park</p>
<p class="category-cases">Infrastructure for All</p>
<p class="category-cases">Leveraging the Landscape to Manage Water</p>
<p class="category-cases">Revitalizing Communities with Parks</p>
<p class="category-cases">Urban Forests = Cleaner, Cooler Air</p>
</ul>
</li>
<li class="dropdown cases educations">
<a class="dropdown-toggle" href="education.html" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false" id="main-nav">Education</a>
<ul style="padding-right:0;" class="dropdown-menu cases-body educations-drop">
<p style="padding-top:15px; " class="category-cases">Brownfield Restoration / Ecosystem Rehabilitation</p>
<p class="category-cases">Design for Active Living</p>
<p class="category-cases">Designing for Biodiversity</p>
<p class="category-cases">Energy Efficiency</p>
<p class="category-cases">Green Infrastructure</p>
<p class="category-cases">Incorporating Sustainable Materials</p>
<p class="category-cases">Transforming Transportation Infrastructure</p>
<p class="category-cases">Urban Agriculture</p>
<p class="category-cases">Urban Forestry</p>
<p class="category-cases">Urban Parks</p>
</ul>
</li>
I tried this script but it didnt work.
$('.dropdown .dropdown-toggle a').on('click', function(e) {
e.preventDefault();
window.location.href = $(this).attr('href');
})
Any ideas?
Site is here
Your selector is incorrect
You have:
$('.dropdown .dropdown-toggle a')
which is looking for a tags inside of .dropdown-toggle class elements, but it is actually your a tag that has the class.
You want:
$('.dropdown a.dropdown-toggle')
to select a elements with the .dropdown-toggle class
Just remove "data-toggle="dropdown"", But as say gwar9 in the comment that will prevent dropdown opening on mobile. So if you want that work for both you need detect if the device is mobile or not if it is not you erase the data toggle attribute.
I've created a jsfiddle to demonstrate how you could meet your requirements.
http://jsfiddle.net/DarrenS/pcav6v1g/
As you explained, you have a UX requirement to allow the following;
On Hover of the main menu, expand the menu to show sub menu items.
On Click of the main menu, follow the main menu link.
I explained that this is not default Bootstrap behaviour and the limitation of hover on touch devices.
To implement this solution I am using Modernizr to detect touch and then adding some custom jQuery to attach hover() and click() events to the menu.
I've implemented it this way because I still wanted to allow larger touch devices (such as a tablet) to access the sub menu. Which they wouldn't be able to do if you simply added a click event handler to the main menu.
//Non-Touch devices
//Hover expands menu (non default Bootstrap behaviour)
$('html.no-touch div.btn-group').hover(function(e) {
$(this).toggleClass('open');
});
//Non-Touch devices
//Click follows main link (non default Bootstrap behaviour)
$('html.no-touch div.btn-group a.dropdown-toggle').on('click', function(e) {
e.preventDefault();
window.location.href = $(this).attr('href');
})
//Touch devices
//Touch (click) expands menu (default Bootstrap behaviour)
//Touch devices
//Allow touch (click) to follows main link when menu open (non default Bootstrap behaviour)
$('html.touch div.btn-group.open a.dropdown-toggle').on('click', function(e) {
e.preventDefault();
window.location.href = $(this).attr('href');
})
.dropdown-menu{
margin-top: 0;
}
<div class="btn-group">
<a href="/page.html" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Google <span class="caret"></span>
</a>
<ul class="dropdown-menu">
<li>Facebook</li>
<li>Twitter</li>
<li>LinkedIn</li>
</ul>
</div>
I encountered this issue too, but realised that changing the behaviour would make the site harder to use for mobile users (who don't have a mouse to hover over controls). So, instead I inserted an "Overview" entry to the drop-down menu that links to the parent page. This makes the parent page clickable on all device types.
Details here: https://keasigmadelta.co.nz/blog/the-bootstrap-drop-down-menu-solution

Bootstrap dropdown selection makes screen jump

So I'm using bootstrap for my website and I have many div's on each page with a dropdown on each that change the information inside the div from a chart to a table and vise-versa. This works fine except when the user selects an option from the drop down the screen seems to "jump", putting that div at the top of the screen. I found a similar issue for someone else saying it has something to do with the anchor tag(#), but I believe I need mine since the drop down does refer to something.
DROPDOWN:
<div class="dropdown">
<button class="btn btn-warning dropdown-toggle btn-xs" type="button" id="dropdownMenuGraphOneSmall" data-toggle="dropdown" aria-expanded="true">Graph One Options<span class="caret"></span>
</button>
<ul class="dropdown-menu" role="menu" aria-labelledby="dropdownMenuGraphOneSmall">
<!--DROPDOWN MENU-->
<li role="presentation">
<a role="menuitem" tabindex="-1" href="#graphOneData">Data</a>
</li>
<li role="presentation">
<a role="menuitem" tabindex="-1" href="#graphOneChart">Chart</a>
</li>
<li role="presentation">
<a data-toggle="modal" data-target="#enlargeGraphOneModal" role="menuitem" tabindex="-1">Maximize</a>
</li>
<li role="presentation">
<a class="collapse-link" role="menuitem" tabindex="-1" href="#graphOneCollapse">Collapse</a>
</li>
</ul>
</div>
CONTENT IT CALLS:
<div class="content active row" id="graphOneChart">
............
</div>
<div class="content" id="graphOneData">
............
</div>
To keep the page from jumping, you can remove the href="" altogether, and just keep the a tag empty like this <a>, then it wont jump.
If you have to keep the href tag, you can use the e.preventDefault() in your click or on method.
When you use an anchor tag, <a>, it is going to automatically go to the location that the href tag is pointing to. If your link is pointing to an id on the page, the link is going to scroll the screen to the element the link is pointing to. If you want to use the link to call a function, leave the href attribute empty, href="".
If you use a hash # in an anchor, the browser will automatically scroll to the element with the corresponding id.
For example, clicking on:
Data
Will cause the page to jump to:
<div id="graphOneData"></div>
To stop this happening, either change the id of the div or the href of the anchor.

Twitter Bootstrap Dropdown with Tabs inside

I'm trying to make a dropdown menu with tabs inside of it. The problem is the dropdown closes when I click a tab. See this demo: http://jsfiddle.net/timrpeterson/pv2Lc/2/. (code reproduced below).
The cited suggestion to stopPropagation() on the tabs anchors doesn't seem to help. Is there a better way?
<script src='http://netdna.bootstrapcdn.com/bootstrap/3.1.0/js/bootstrap.min.js'></script>
<link href='http://netdna.bootstrapcdn.com/bootstrap/3.1.0/css/bootstrap.min.css' rel="stylesheet" type="text/css"/>
<div class="dropdown">
<a id="dLabel" role="button" data-toggle="dropdown" data-target="#" href="/page.html">
Dropdown <span class="caret"></span>
</a>
<ul class="dropdown-menu" role="menu" aria-labelledby="dLabel">
<ul class="nav nav-tabs">
<li class="active">Home </li>
<li>Profile</li>
<li>Messages</li>
</ul>
<!-- Tab panes -->
<div class="tab-content">
<div class="tab-pane active" id="home">HOME asdfasdfsda</div>
<div class="tab-pane" id="profile">PROFILE asdfafas</div>
<div class="tab-pane" id="messages">MESSAGES asdfdas</div>
</div>
</ul>
</div>
The cited suggestion doesn't work because the .tab('show') method should be invoked on the actual tab (i.e., the link) instead of the tab pane.
So the code should be:
$('.dropdown-menu a[data-toggle="tab"]').click(function (e) {
e.stopPropagation()
$(this).tab('show')
})
Here is an updated fiddle: http://jsfiddle.net/pv2Lc/6/
Use the specific bootstrap events : the hide.bs.dropdown (triggered when the dropdown is about to close) allows you to cancel the "hide" action by calling e.preventDefault(). (doc here, list of specific bootstrap events for scrolldown components)
You can activate a special flag when the user clicks on a tab, and check that flag in the hide.bs.dropdown event on the dropdown :
$('#myTabs').on('click', '.nav-tabs a', function(){
// set a special class on the '.dropdown' element
$(this).closest('.dropdown').addClass('dontClose');
})
$('#myDropDown').on('hide.bs.dropdown', function(e) {
if ( $(this).hasClass('dontClose') ){
e.preventDefault();
}
$(this).removeClass('dontClose');
});
fiddle
(I added html ids to your example, change the selectors according to your needs)

Categories