I'm attaching handler to the Bootstrap hidden.bs.modal
event to detect when the modal is closed, but it can be closed in multiple ways:
- Explicitly close it via
$('#modal').modal('hide')
or$('#modal').modal('toggle')
; - Clicking on modal's backdrop part (if allowed);
- Via data attributes e.g.
data-dismiss="modal"
Is there a way to detect which of the options was used? Inside the hidden.bs.modal
handler e.target
always appears to be div#modal
I'm attaching handler to the Bootstrap hidden.bs.modal
event to detect when the modal is closed, but it can be closed in multiple ways:
- Explicitly close it via
$('#modal').modal('hide')
or$('#modal').modal('toggle')
; - Clicking on modal's backdrop part (if allowed);
- Via data attributes e.g.
data-dismiss="modal"
Is there a way to detect which of the options was used? Inside the hidden.bs.modal
handler e.target
always appears to be div#modal
- As far as I know, no. But I think a more import question is - why does it matter? – Leroy Stav Commented Jan 21, 2019 at 0:31
- @LeroStav If you have a dialog where some user input is required, you need to know how the user closed it. You wouldn't want to act on user input from a dialog that was canceled. – braab Commented Jan 17, 2023 at 5:48
2 Answers
Reset to default 13The thing is that hidden.bs.modal
is an event that fires once the modal has been closed. So that is not the click
event the user triggered from the close button, the corner X or the overlay...
That said, you can use the click
event to store where the user clicked in a variable and milliseconds after, when the hidden.bs.modal
fires, use the variable.
Demo:
$(document).ready(function(){
// Variable to be set on click on the modal... Then used when the modal hidden event fires
var modalClosingMethod = "Programmatically";
// On modal click, determine where the click occurs and set the variable accordingly
$('#exampleModal').on('click', function (e) {
if ($(e.target).parent().attr("data-dismiss")){
modalClosingMethod = "by Corner X";
}
else if ($(e.target).hasClass("btn-secondary")){
modalClosingMethod = "by Close Button";
}
else{
modalClosingMethod = "by Background Overlay";
}
// Restore the variable "default" value
setTimeout(function(){
modalClosingMethod = "Programmatically";
},500);
});
// Modal hidden event fired
$('#exampleModal').on('hidden.bs.modal', function () {
console.log("Modal closed "+modalClosingMethod);
});
// Closing programmatically example
$('#exampleModal').modal("show");
setTimeout(function(){
$('#exampleModal').modal("hide");
},1000);
});
<link href="https://stackpath.bootstrapcdn./bootstrap/4.2.1/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare./ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://stackpath.bootstrapcdn./bootstrap/4.2.1/js/bootstrap.min.js"></script>
<!-- Button trigger modal -->
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#exampleModal">
Launch demo modal
</button>
<!-- Modal -->
<div class="modal fade" id="exampleModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">Modal title</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
...
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary">Save changes</button>
</div>
</div>
</div>
</div>
CodePen
You can use the hide.bs.modal
event to capture the document.activeElement
. If you have multiple buttons all of which include data-bs-dismiss='modal'
, this will allow you to determine which of those buttons was pressed. This avoids the need for onclick=
approaches or additional event handlers.
It seems it would be more elegant if the Event
object for the hide.bs.modal
event had a .relatedTarget
or similar which contained the triggering element, but alas that's not the case right now.
The example below assumes jQuery with $
:
$(() => {
var $dlg = $("#myBootstrapModalDialog");
var $closeElement;
$dlg.on('show.bs.modal', (e) => {
// maybe do something to initialize the modal here...
})
.on('hide.bs.modal', (e) => {
$closeElement = $(document.activeElement);
})
.on('hidden.bs.modal', (e) => {
var id = $closeElement.attr('id');
// do something depending on the id...
if (id === 'btn-save') {
// save something
}
$closeElement = null;
});
});
Sample HTML:
<div class="modal fade"
id="myBootstrapModalDialog"
tabindex="-1"
aria-labelledby="myDialogTitle"
aria-hidden="true">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content rounded-0 mx-auto">
<div class="modal-header">
<h3 class="modal-title text-primary" id="myDialogTitle">
Save this stuff?
</h3>
<button id="btn-close" type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body px-3">
Are you sure you want to save this stuff?
</div>
<div class="modal-footer">
<button id="btn-cancel" type="button" class="btn btn-link" data-bs-dismiss="modal">
Cancel
</button>
<button id="btn-save" type="button" class="btn btn-secondary" data-bs-dismiss="modal">
Save
</button>
</div>
</div>
</div>
</div>