Bootstrap dropdown not working when parent has a click event - javascript

I have a Bootstrap dropdown menu inside a container that triggers an event--the way I want it to work is, if you click the dropdown button, the menu items are displayed as normal. If you click anywhere else within the container, the parent event should be triggered (in this case displaying a Javascript alert). Instead, the event is being triggered even when I click the dropdown button.
Is there some way I can get the dropdown click event to "override" its parent event, so that if it's clicked its own evnet will be triggered the parent event won't?
<div class='main-container' onClick='alert("a thing was clicked!")'>
<div class="dropdown">
<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 1</a>
<a class="dropdown-item" href="#">Action 2</a>
<a class="dropdown-item" href="#">Action 3</a>
</div>
</div>
</div>
http://jsfiddle.net/0fpbcy2L/12/

Related

How to prevent event bubbling in blazor server side?

In my blazor server side application I have cards representing datasets, which the user can manage.
They look like this:
The relevant code looks like this:
<div class="card h-100 text-dark" #onclick="() => OnDatasetSelected(dataset)">
<!-- header image -->
<div class="card-body position-relative">
<div class="dropdown dropstart">
<button type="button" data-bs-toggle="dropdown" aria-expanded="false">
<i class="bi bi-three-dots-vertical"></i>
</button>
<ul class="dropdown-menu">
<!-- menu content -->
</div>
<!-- card content -->
</div>
As one can see from the code, I'm currently adding the context menu (three vertical dots) using the template code from bootstraps dropdown (dropleft in my case) component.
This works fine - or rather it would if it weren't for the #onclick event on the card, which calls the code to select the dataset and navigate to another page.
Question basically is: How can I prevent the OnClick event, if an element inside is being clicked on. I guess, what I'm asking is: How can I prevent event bubbling in HTML? Is it possible without adding code to the inner dropdown element (display of bootstrap-dropdowns is done with popper.js, which is external)
Lol, found the answer here 5 minutes after posting:
Simply use onclick="event.stopPropagation();" to prevent the event bubbling.
So in the end I just add this to the dropdown container:
<div class="dropdown dropstart position-absolute top-0 end-0 " onclick="event.stopPropagation();">
<button type="button" class=" btn btn-outline-secondary fs-5 p-0 m-2 border-0"
data-bs-toggle="dropdown" aria-expanded="false">
<i class="bi bi-three-dots-vertical"></i>
</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>
And now I can click my menu button:
Important Edit:
In case you have issues with onclick="event.stopPropagation();" preventing the #onclick event of the inner button to be fired, one can use the following directly at the inner button:
<button type="button" #onclick="MyFunction"
#onclick:stopPropagation="true">
Button Text
</button>
This will call MyFunction when clicking the button, but prevents the event to be propagated to the parent elements.

How to link event logic to Bootstrap 5 dropdown clicks?

How do you attach an "onclick" event to a Bootstrap 5 dropdown so you can perform application logic according to which dropdown menu item was clicked?
The docs explain how to receive events when the dropdown is open and closed, but there doesn't appear to be any way to find the clicked menu item. I even tried attaching a jQuery click event to the menu items, but that appears to be blocked.
My dropdown looks like:
<div class="mb-3">
<button class="btn btn-secondary dropdown-toggle" type="button" id="tuningSelectButton" data-bs-toggle="dropdown" aria-expanded="false">
Select Tuning
</button>
<ul id="tuning-options" class="dropdown-menu" aria-labelledby="tuningSelectButton">
<li><a class="dropdown-item" href="#" data-tuning="value1">1</a></li>
<li><a class="dropdown-item" href="#" data-tuning="value2">2</a></li>
<li><a class="dropdown-item" href="#" data-tuning="value3">3</a></li>
</ul>
</div>
and my Javascript looks like:
$('#tuning-options li a').change(function(){
var el = $(this);
console.log(el.val())
});
First of all, you're listening for change events on <a> elements. Change events are only fired on form elements (<input>s, <textarea>s and <select>s), when their native value attribute changes value. Links do not have a native value attribute, therefore change is never fired on them.
jQuery documentation for change() also states form elements are the only valid targets for this event.
For the same reason, running jQuery's .val() on an <a> will always return an empty string (I would have guessed undefined. Still falsey value).
Looking for a more suitable event to listen to, found this in the docs:
hide.bs.dropdown and hidden.bs.dropdown events have a clickEvent property (only when the original Event type is click) that contains an Event Object for the click event.
Last, but not least, Bootstrap dropdown relies on its markup (HTML structure). In particular, both .dropdown-toggle and .dropdown-menu should be wrapped in a .dropdown element. Bootstrap uses it as dropdown events emitter.
Additionally, you should move tuning-options id from .dropdown-menu to the wrapper.
At which point this code will work:
$('#tuning-options').on('hide.bs.dropdown', ({ clickEvent }) => {
if (clickEvent?.target) {
console.log($(clickEvent.target).data('tuning'))
}
})
Working example:
$('#tuning-options').on('hide.bs.dropdown', ({ clickEvent }) => {
if (clickEvent?.target) {
console.log($(clickEvent.target).data('tuning'))
}
})
<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.0.2/dist/js/bootstrap.bundle.min.js"></script>
<link href="https://cdn.jsdelivr.net/npm/bootstrap#5.0.2/dist/css/bootstrap.min.css" rel="stylesheet"/>
<div class="dropdown" id="tuning-options">
<button class="btn btn-secondary dropdown-toggle" type="button" id="dmb1" data-bs-toggle="dropdown" aria-expanded="false">
Select tuning
</button>
<ul class="dropdown-menu" aria-labelledby="dmb1">
<li><a class="dropdown-item" data-tuning="value1" href="#">Tuning 1</a></li>
<li><a class="dropdown-item" data-tuning="value2" href="#">Tuning 2</a></li>
<li><a class="dropdown-item" data-tuning="value3" href="#">Tuning 3</a></li>
</ul>
</div>
Additional note: Although the specs indicate this code should only work for click events, it also works when a dropdown menu item is selected using a keyboard (most likely Bootstrap fires a programmatic click event when a dropdown menu item is selected by keyboard).
This can be done with vanilla js as well
window.addEventListener('load', function () {
const myDropdown = document.getElementById('dmb1')
myDropdown.addEventListener('hide.bs.dropdown', event => {
console.log(event.clickEvent.path[0].getAttribute('value'))
})
})
<link href="https://cdn.jsdelivr.net/npm/bootstrap#5.1.3/dist/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://cdn.jsdelivr.net/npm/bootstrap#5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script>
<div class="dropdown" id="tuning-options">
<button class="btn btn-secondary dropdown-toggle" type="button" id="dmb1" data-bs-toggle="dropdown" aria-expanded="false">
Select tuning
</button>
<ul class="dropdown-menu" aria-labelledby="dmb1">
<li><a class="dropdown-item" value="value1" href="#">Tuning 1</a></li>
<li><a class="dropdown-item" value="value2" href="#">Tuning 2</a></li>
<li><a class="dropdown-item" value="value3" href="#">Tuning 3</a></li>
</ul>
</div>
If you're trying to get the value in data-tuning then you should change
console.log(el.val())
into
console.log(el.data('tuning'))
Check out JQuery's API Documentation to learn more.
https://api.jquery.com/data/

Bootstrap Dropdown Button Changes Position

I was following the documentation found here: https://getbootstrap.com/docs/4.1/components/dropdowns/
and added the following dropdown button:
<div class="dropdown">
<button class="btn btn-secondary dropdown-toggle" type="button" id="dropdownMenu1" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Example 1</button>
</div>
The issue I'm having is that when the button is clicked on to display the dropdown-menu, the button changes it's position. This happens with both dropdown buttons I have.
Buttons Without Dropdown Clicked
Dropdown Clicked & Button Changed Position Example 1
Dropdown Clicked & Button Changed Position Example 2
You can see example code of this issue occurring: https://codepen.io/danfuentes/pen/MWaYOgz
How can I get it so that the button stays in place with the menu items appearing below it?
Surround your elements in a parent div element with btn-grp class like so:
<div class="btn-group" role="group">
<button id="btnGroupDrop1" type="button" class="btn btn-secondary dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Dropdown
</button>
<div class="dropdown-menu" aria-labelledby="btnGroupDrop1">
<a class="dropdown-item" href="#">Dropdown link</a>
<a class="dropdown-item" href="#">Dropdown link</a>
</div>
</div>
You will need to provide the HTML that surrounds the button element along with the css for all of those elements.
Can you update your question with this information so that we can see what's going on beyond just the button tag?
Update after seeing codepen:
You had a couple of div tags in the incorrect place, please see below for the solution:
<div class="btn-group">
<div class="dropdown">
<button class="btn btn-secondary dropdown-toggle" type="button" id="dropdownMenu2" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Example 1</button>
<div class="dropdown-menu" aria-labelledby="dropdownMenu2">
<a class="dropdown-item" href="#">Dropdown tesdt</a>
<a class="dropdown-item" href="#">Dropdown 2</a>
<a class="dropdown-item" href="#">Dropdown 3</a>
<a class="dropdown-item" href="#">Dropdown 4</a>
<a class="dropdown-item" href="#">Dropdown 5</a>
</div>
</div>
<div class="dropdown">
<button class="btn btn-secondary dropdown-toggle" type="button" id="dropdownMenu2" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Example 2</button>
<div class="dropdown-menu" aria-labelledby="dropdownMenu2">
<a class="dropdown-item" href="#">Dropdown 1</a>
<a class="dropdown-item" href="#">Dropdown 2</a>
<a class="dropdown-item" href="#">Dropdown 3</a>
<a class="dropdown-item" href="#">Dropdown 4</a>
<a class="dropdown-item" href="#">Dropdown 5</a>
</div>
</div>
<button type="button" class="btn btn-primary" onclick="#">Regular Button 1</button>
<button type="button" class="btn btn-primary" onclick="#">Regular Button 2</button>
</div>
Basically you want to wrap all of your buttons within a single div with a class of "dropdown".
The dropdown class declares the css position:relative which will ensure the positioning is correct for the dropdowns to display correctly without shifting other elements on the page around.
Update 2: I've updated the HTML above to resolve the new problem you encountered. You will need to wrap the individual dropdowns in div's with the class of "dropdown" to ensure they can have individual links. To make sure they do not shift from their intended positions all of the buttons are now wrapped in a div with the class of "btn-group".
The "btn-group" class ensures the position is set to relative however by default it introduces a few other styling quirks such as removing the spacing between the buttons. In order to override this I've also added the following to the css:
button {
margin: 10px !important
}
The above grabs all buttons on the page and gives them an all-round margin of 10px.
If you want to overwrite any bootstrap class stylings you will need to set the !important property on those elements.
Codepen with the solution:
https://codepen.io/pen/pojvprg

Multiple Bootstrap dropdown in same div class

Is it possible to have multiple dropdown menus in the same nav class in bootstrap, without putting each menu item in a separate div?
What is happening is that when I click on the dropdown menu , the same dropdown opens up every time( I have two dropdowns for two separate menu items)
I have tried using data-target to open only the dropdown with a specific id but this returns a console error.
<nav>
<a>Menu item 1</a>
<a>Menu item 2</a>
<a class="dropdown dropdown-toggle" href="#" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Menu item 3(dropdown menu 1)</a>
<div class="dropdown-menu" aria-labelledby="dropdown">
<a class="dropdown-item" href="/">dropdown item 1</a>
</div>
<a class="dropdown dropdown-toggle" href="#" style= "display:none;" id="certdropdown" data-toggle="dropdown" data-target="#dropdown2" aria-haspopup="true" aria-expanded="false">Menu item 3 ( dropdown menu 2)</a>
<div class="dropdown-menu" aria-labelledby="dropdown" id ="dropdown2">
<a class="dropdown-item" href="/">dropdown item 1</a>
</div></nav>
If i separate both menu items in separate div, it works but my css gets ruined
No, it's not possible to have two dropdown menus inside the same div. They need to be separated since the code to toggle them looks for the first element in the parent div of the button/anchor. So if they are in the same parent div only the first will be toggled.
Since you haven't provided what part of your CSS gets ruined, I'm gonna guess two problems you might encounter with this.
The dropdown buttons gets wrapped to the next row.
You're selecting links inside your nav by doing nav > a, which ignores the links inside the <div class="dropdown"></div> or you're selecting links inside your nav by doing nav a, which includes the links inside the dropdown-menu.
First solution:
If your dropdown buttons/links gets placed on their own row, it's because they have the display value of block. Add the class d-inline to the <div class="dropdown"> to fix this.
Second solution:
Select and style your links inside the nav with this code:
nav a:not(.dropdown-item) {
// styling
}
This will ignore the links inside the dropdown but style all other links.
If you're having some other problem with your CSS please explain what it is and I will try to help you.
The suggestion here looks good. Essentially, you need to use btn-groups, as shown in this example and just above it in the docs.
Using your code with the display none style and the unnecessary id taken off of the second dropdown:
<nav>
<a>Menu item 1</a>
<a>Menu item 2</a>
<div class="btn-group">
<a class="dropdown dropdown-toggle" href="#" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Menu item 3(dropdown menu 1)
</a>
<div class="dropdown-menu" aria-labelledby="dropdown">
<a class="dropdown-item" href="/">dropdown item 1</a>
</div>
</div>
<div class="btn-group">
<a class="dropdown dropdown-toggle" href="#" id="certdropdown" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Menu item 3 ( dropdown menu 2)
</a>
<div class="dropdown-menu" aria-labelledby="dropdown">
<a class="dropdown-item" href="/">dropdown item 1</a>
</div>
</div>
</nav>
You can read more specifics about button groups here.

Clicking caret icon inside bootstrap link does not work

Using Bootstrap v3.3.7 and jQuery v1.12.4, I am creating a component which activates a HTML popover.
Please see the code below.
Clicking the button activates the popover. However clicking the caret icon within the button does not do anything. Any idea why and how to resolve this?
Click here for the jsfiddle.
<a role="button" class="btn btn-default po" data-poc="#html1">Test 1 <span class="caret"></span></a>
<a role="button" class="btn btn-default po" data-poc="#html2">Test 2 <span class="caret"></span></a>
<div id="html1" class="hide">
<strong>This</strong> is a test!
</div>
<div id="html2" class="hide">
<strong>This</strong> is another test!
</div>
Use this
<a id="po1" class="btn btn-default" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Test <span class="caret"></span></a>
click here

Categories