1

I have a problem with my Bootstrap modals. I am using an $.ajax call, so I can send POST data to a separate .php file, to be displayed in the opened modal. I've been using Bootstrap 3, and I had no bugs, but when I upgraded to Bootstrap 4, my modals will not close.

Originally I found techniques that used show.bs.modal here on StackOverflow, as I did my research to build my website. I stripped down my code as simple as I could for testing purposes, so I can replicate it here in this question. In the following code, the button titled "Launch demo modal" will open and close, but the "Launch ajax demo modal" will only open (I have to refresh to make it go away).

I've worked very hard to follow Bootstrap's advice on how to arrange the links and references to their libraries. Please notice there is a file called test-modal.php involved in the show.bs.modal "on" function.

Please see the stripped down test code that I am trying, below:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta.3/css/bootstrap.min.css" integrity="sha384-Zug+QiDoJOrZ5t4lssLdxGhVrurbmBWopoEl+M6BdEfwnCJZtKxi1KgxUyJq13dy" crossorigin="anonymous">

    <link rel="icon" href="http://si.hclibrary.org/wp-content/uploads/2017/02/Icon_SmallSi-01.png" sizes="32x32">
    <title>HCLS IT Helpdesk Request Site</title>
</head>

<body>

<!-- Button trigger modal -->
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#exampleModal">
  Launch demo modal
</button>

<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#exampleModal2">
  Launch ajax demo modal
</button>

<!-- Modal -->
<div class="modal fade" id="exampleModal" tabindex="-1" role="dialog" 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">&times;</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>

<div class="modal fade" id="exampleModal2" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true"></div>

<script src="https://code.jquery.com/jquery-3.2.1.js" integrity="sha256-DZAnKJ/6XZ9si04Hgrsxu/8s717jcIzLy3oi35EouyE=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta.3/js/bootstrap.min.js" integrity="sha384-a5N7Y/aK3qNeh15eJKGWxsqtnX/wWdSZSKp+81YjTmS15nvnvxKHuzaWwXHDli+4" crossorigin="anonymous"></script>

<script>
$( document ).ready(function() {
    $('#exampleModal2').on('show.bs.modal', function(e) { 
        $.ajax({
            type:'post',
            url:'test-modal.php',
            data:{
                id:"id",
                type:"type"
            },
            success:function(data) {
                $('#exampleModal2').html(data);
            }
        });
    });
});
</script>

</body>
</html>

And my test-modal.php file is very simple:

  <div class="modal-dialog" role="document">
    <div class="modal-content">
      <div class="modal-header">
        <h5 class="modal-title" id="exampleModalLabel">Ajax Modal title</h5>
        <button type="button" class="close" data-dismiss="modal" aria-label="Close">
          <span aria-hidden="true">&times;</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>

Has anyone else experienced this issue where the modal won't close like it normally should? Is there something in Bootstrap 4 that is deprecated, so that this is not supposed to work like it used to? Or is there an alternative way I should be sending POST variables to an opened modal? I've been stuck on this for a long time and all advice is very appreciated. Please let me know if I should include more information.

Louys Patrice Bessette
  • 27,837
  • 5
  • 32
  • 57
Mark
  • 2,391
  • 1
  • 13
  • 20
  • 1
    The modal elements are replaced by your ajax call... So the new HTML elements are not parsed by bootstrap. Why not just load the modal body? – Louys Patrice Bessette Jan 22 '18 at 18:52
  • @LouysPatriceBessette Is it possible to load the modal body with variable passed to it, say by POST? – Mark Jan 22 '18 at 18:53
  • @LouysPatriceBessette That definitely seems logical now that you mention it. I wonder why it used to work before with Bootstrap 3. – Mark Jan 22 '18 at 18:54
  • 1
    In Ajax `success`, you could load only the body using `$('#exampleModal2 .modal-body').html(data);` – Louys Patrice Bessette Jan 22 '18 at 18:55
  • @LouysPatriceBessette Yes, that worked nicely. It closes now. :) – Mark Jan 22 '18 at 19:07
  • @LouysPatriceBessette How did you know that the new HTML elements wouldn't be parsed by Bootstrap? I'm confused because it seems like the CSS and JS would still be part of the HTML body, which contains the modals. – Mark Jan 22 '18 at 19:09
  • 1
    Bootstrap is a JS script that runs onload. It's always the same issue with dynamic elements that do not exist when the script runs. Read that [famous answer](https://stackoverflow.com/questions/203198/event-binding-on-dynamically-created-elements) ;) – Louys Patrice Bessette Jan 22 '18 at 19:13
  • But here, you just do not control the event handlers, since that is Bootstrap's job. ;) – Louys Patrice Bessette Jan 22 '18 at 19:19

1 Answers1

4

Do not replace the whole modal markup...

Since the event handlers are binded by Bootstrap on load, if you "replace" them, the new elements won't be binded because Bootstrap already ran.

Just load the modal's body using $('#exampleModal2 .modal-body').html(data); in the Ajax success callback.

If you wish to change the title, you can do it using:

$('#exampleModal2 .modal-title').html("Ajax loaded this new title.");

Look for a JSON data response, if you need to send the title AND the body content from the server resource.

A JSON data format will allow you to send more than one "data" at once.
;)

Louys Patrice Bessette
  • 27,837
  • 5
  • 32
  • 57