Reputation: 744
I am trying to add a bootstrap dropdown inside another clickable parent. It's kind of tricky I guess. Here is the Codepen I created with the issue recreated.
Codepen with the issue recreated
Expected behavior: On clicking the dropdown, the dropdown will fire, so will by clicking the other button (optional if too tricky) and none will trigger a click on the parent.
<div class="card-body parent" style="min-height: 300px;">
<!-- ORIGINAL DROPPER BUTTON -->
<div class="dropdown original-dropper mb-5">
<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>
</div>
</div>
<!-- OTHER DROPPER BUTTON -->
<button class="btn btn-danger other-dropper mt-5 d-inline">Other Button</button>
</div>
JS:
$('.parent').on('click', function(e) {
$(this).css('backgroundColor', 'darkorange');
});
$('.other-dropper').on('click', function(e) {
e.stopPropagation();
$('.original-dropper .dropdown-toggle').dropdown();
console.log('clicked');
});
Upvotes: 3
Views: 2025
Reputation: 53193
First, it's better to filter an event at the target instead of calling stopPropagation
. If you stop propagation of event, it prevents any other global listeners from capturing them. For example, other dropdowns will not close if click event propagation was stopped.
So instead I introduced this neat filter method, that allows you to check if the source of event or it's parents has a class:
/**
* Checks if any of parent nodes of elm has a class name
* @param {HTMLElement} elm the starting node
* @param {string} className
* @param {HTMLElement} stopAtElm if this parent is reached, search stops
**/
function treeHasClass(elm, className, stopAtElm) {
while(elm != null && elm != stopAtElm) {
if(elm.classList.contains(className)) {
return true;
}
elm = elm.parentNode;
}
return false;
}
Unfortunately you still need stopPropagation
for the button, else the click event would close the drop-down immediately.
Second, you want to call .dropdown("toggle")
:
$('.original-dropper .dropdown-toggle').dropdown("toggle");
All together, the javascript is:
$('.parent').on('click', function(e) {
// Do not trigger if target elm or it's child has `no-orange` class
if(!treeHasClass(e.target, "no-orange", this)) {
$(this).css('backgroundColor', 'darkorange');
}
});
$('.other-dropper').on('click', function(e) {
e.stopPropagation();
e.preventDefault();
$('.original-dropper .dropdown-toggle').dropdown("toggle");
console.log('clicked');
});
And you want to put no-orange
to elements that shouldn't change background color:
<button class="no-orange btn btn-danger other-dropper mt-5 d-inline">Other Button</button>
All together here: https://codepen.io/MXXIV/pen/rNBpepd
Upvotes: 1