How do I know which button is clicked when the bootstrap modal closes?

JavascriptJqueryHtmlTwitter Bootstrap

Javascript Problem Overview


Here is my modal html code:

<div class="modal fade" id="delete-file-modal" role="dialog">
	<div class="modal-dialog">
		<div class="modal-content">
			<form class="form-horizontal" method="post" id="delete_file_form">
			
				<div class="modal-body">
					Are you sure you want to delete this file?	
				</div>	
				
				<div class="modal-footer">
					<button data-dismiss="modal" class="btn btn-danger" name="in_confirm_insert" id="confirm-delete-button">Delete</button>
					<button data-dismiss="modal" class="btn btn-default" name="in_confirm_insert" id="cancel-delete-button">Cancel</button>
				</div>
				
			</form>
		</div>
	</div>
</div>

and here is my javascript code:

$('#delete-file-modal').on('hidden.bs.modal', function (e) {

    var delete_button = $(e.target).is("#confirm-delete-button");
    	
    if(delete_button === true) {
        //delete file
    	alert("file deleted.");
	} else {
		alert("delete failed.");
	};
});

I need to be able to check if the delete button is clicked when the delete-file-modal is closed. Is there something else missing in my javascript code?

Javascript Solutions


Solution 1 - Javascript

Option #1

Within the hidden.bs.modal event listener, event.target refers to the modal element that is hidden, not the clicked element that triggered the event.

If you want to determine which button triggered the modal to close, one option is to add event listeners to the button elements inside of the modal. Then inside of the button event listener you could listen to the hidden.bs.modal event on the parent #modal element in order to determine if the modal was closed. Since the hidden.bs.modal event listener is inside of the button click event listener, you still have a reference to the element that triggered the click event.

Example Here

$('#delete-file-modal .modal-footer button').on('click', function(event) {
  var $button = $(event.target); // The clicked button

  $(this).closest('.modal').one('hidden.bs.modal', function() {
    // Fire if the button element 
    console.log('The button that closed the modal is: ', $button);
  });
});

It's also worth mentioning that the .one() method will only fire the event once each time it is attached (which is exactly what we want). Otherwise, if you used .on() or .click() to attach the event, then the event could fire multiple times since it is reattached each time the click event listener is fired.


Option #2

According to the relevant Bootstrap documentation, the show.bs.modal/shown.bs.modal events have a relatedTarget property attached to the event.

>If caused by a click, the clicked element is available as the relatedTarget property of the event.

Thus, you can determine the element that triggered the modal to open event by accessing event.relatedTarget inside of the modal show event listener:

Example Here

$('#delete-file-modal').on('show.bs.modal', function (event) {
    console.log(event.relatedTarget);
});

Keep in mind that the relatedTarget property is only associated with the modal show events. It would be nice if they had a property like that associated with the hide.bs.modal/hidden.bs.modal events. As of writing this, there currently isn't.


Option #3

As Andrew pointed out in the comments below this answer, you can also check to see which element on the page has focus by accessing document.activeElement.

In the snippet below, an event listener is attached to the modal element for the show and hide events. When the event is triggered, a check is made to see if the currently focused on element has a [data-toggle] or [data-dismiss] attribute (which implies that it did in fact trigger the event).

Example Here

$('#delete-file-modal').on('hide.bs.modal show.bs.modal', function(event) {
  var $activeElement = $(document.activeElement);
  
  if ($activeElement.is('[data-toggle], [data-dismiss]')) {
    console.log($activeElement);
  }
});

If you are listening to both show/hide events, like in the example above, and you want to differentiate between the events, you could check event.type:

Example Here

$('#delete-file-modal').on('hide.bs.modal show.bs.modal', function(event) {
  var $activeElement = $(document.activeElement);
  
  if ($activeElement.is('[data-toggle], [data-dismiss]')) {
    if (event.type === 'hide') {
      // Do something with the button that closed the modal
      console.log('The button that closed the modal is: ', $activeElement);
    }
    
    if (event.type === 'show') {
      // Do something with the button that opened the modal
      console.log('The button that opened the modal is: ', $activeElement);
    }
  }
});

Solution 2 - Javascript

This works too:

$('#myModal').on('hide.bs.modal', function (e) { 
var tmpid = $(document.activeElement).attr('id'); alert(tmpid); 
}); 

It won't get the id of the 'X' on the modal unless you id it. Will return the id of the element which triggers the closing of the modal....

Solution 3 - Javascript

To extend @JoshCrozier's answer:

> It would be nice if they had a property like that associated with the hide.bs.modal/hidden.bs.modal events. As of writing this, there currently isn't


This will emulate a similar behaviour, that attaches the clicked button as relatedTarget for later listeners:

$( '.modal-footer .btn[data-dismiss="modal"]' ).on( 'click', function() {
	var target = this
	
	$( target ).closest( '.modal' )
		.one( 'hide.bs.modal hidden.bs.modal', function( event ) {
			event.relatedTarget = target
		} )
} )

The selector and listener can be further optimized depending on how the modals are used in a project. For example: if you know you're not going to use hide.bs.modal you can just modify hidden.bs.modal's event instead.

Solution 4 - Javascript

The @JoshCrozier answer is good and useful but sometimes we need to Determine witch element triggered the modal to opened/closed AFTER it has been closed. (@Nomad has mentioned to this in the comments below the @JoshCrozier answer).

Also some times we need to determine which link or button in the body or header triggered the modal to close (not just buttons in the footer).

Then i write this solution to mix @JoshCrozier and @Katia answers with my way and improve the final solution:

Add this part to Scripts of your page:

$('body').on('click','.modal .dismiss-modal', function() {
    var closeRelatedTarget = this;
    var $modal = $(closeRelatedTarget).closest('.modal');
    $modal.one('hide.bs.modal hidden.bs.modal', function(event) {
        $modal.data('closeRelatedTarget',closeRelatedTarget);
    });
    $modal.data('closeRelatedTarget','wait');
    $modal.modal('hide');
});
$('body').on('show.bs.modal','.modal', function(event){
    $(this).data('closeRelatedTarget','anElement');
    $(this).data('showRelatedTarget',event.relatedTarget);
});

Now use it easily with simple Event Handlers or Get the target element:

● Determine witch element triggered the modal to show on show and shown (An embed Bootstrap feature):

 $('#MyModal').on('show.bs.modal', function (event) {
     console.log(event.relatedTarget);
 });

and

 $('#MyModal').on('shown.bs.modal', function (event) {
     console.log(event.relatedTarget);
 });

● Determine witch element triggered the modal to close on hidden

 $('#BuyModal').on('hidden.bs.modal', function (event) {
      if($(this).data('closeRelatedTarget')=='wait')
      {return;}
 
      console.log($('#MyModal').data('closeRelatedTarget'));
 });

● Determine witch element triggered the modal to show even after the modal is closed

 console.log($('#MyModal').data('showRelatedTarget'));

● Determine witch element triggered the modal to close even after the modal is closed

 console.log($('#MyModal').data('closeRelatedTarget'));

> Note: Instead of data-dismiss="modal" property use my modal-dismiss class to each element in the model that you can close the model and you want determine it (Don't use both modal-dismiss class and data-dismiss="modal" together). > > Example: <a href="/more_info.html" class="dismiss-modal">More info</a> > > Why? Because data-dismiss="modal" close the model and trigger hide and hidden before we set closeRelatedTarget.

Solution 5 - Javascript

Edited : A solution that works well with BOOTSTRAP 4+ that I haven't seen here, can be adapted with other versions including for v5. May be useful to someone if needed.

<div class="modal-footer">
    <button type="button" class="btn btn-secondary" data-dismiss="modal">Annuler</button>
    <button type="button" class="btn btn-primary" data-dismiss="modal">Valider</button>
</div>

$('#prompt_modal').on('shown.bs.modal', function (event) {
    let buttons = this.querySelectorAll('.btn'); // or others selectors
    buttons.forEach(btn => {
        btn.onclick = () => {
            console.log(btn);
            // do something with btn (textCOntent, dataset, classlist, others) 
            // to detect clicked...
        }
    })
})

Solution 6 - Javascript

We're overthinking this. It's as simple as a standard button handler. The data-dismiss="modal" will make the dialog go away, and we'll still know that the button that we were interested in was clicked.

$('#delete-file-modal').on('click','#delete-file-modal #confirm-delete-button', function (e) {
  e.preventDefault();
  console.log('confirmed delete');
  return false;
});

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionNomadView Question on Stackoverflow
Solution 1 - JavascriptJosh CrozierView Answer on Stackoverflow
Solution 2 - JavascriptAndrewView Answer on Stackoverflow
Solution 3 - JavascriptKataiView Answer on Stackoverflow
Solution 4 - JavascriptRamin BateniView Answer on Stackoverflow
Solution 5 - JavascriptJean GoreneView Answer on Stackoverflow
Solution 6 - JavascriptVolomikeView Answer on Stackoverflow