Bootstrap 5 Datatable - Search box and Modal backdrop issue

Bootstrap 5 Datatable - Search box and Modal backdrop issue

skchandonskchandon Posts: 2Questions: 0Answers: 0
edited May 2022 in Free community support

Test case:
(setup)
setup step 1. Define an api call (_jsURLTasksApi) that returns a json like following:

[{"taskId":2,"taskName":"task 2e"},
{"taskId":3,"taskName":"task 3"},
{"taskId":4,"taskName":"task1"},
{"taskId":8,"taskName":"review"},
{"taskId":9,"taskName":"Stapling"}]

setup step 2. Add a HTML table in the HTML page.

                <div id="tasksList" class="container-fluid tab-pane active">
                    <div class="table-responsive mt-4">
                        <table class="table table-hover table-bordered table-striped" id="tasksTable">
                            <thead>
                                <tr>
                                <th>Task Id</th>
                                <th>Task Name</th>
                                <th>Edit</th>

                                </tr>
                            </thead>
                            <tfoot>
                                <tr>
                                <th>Task Name</th>
                                <th>Active?</th>
                                <th>Edit</th>

                                </tr>
                            </tfoot>

                        </table>
                    </div>
                </div>

setup step 3. Add a modal dialog in the HTML page before the </body> tag

<!-- Edit Dialog-->
<div class="modal fade" id="editEntityModal" tabindex="-1" role="dialog">
  <div class="modal-dialog" role="document">
    <div class="modal-content" id="editEntity">        
      <div class="modal-header">
        <h5 class="modal-title">Edit entityName</h5>
        <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close">
          
        </button>
      </div>
      <div class="modal-body">
          body code here
      </div>
      <div class="modal-footer">
        
        <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
      </div>
      
    </div>
  </div>
</div>

<!--(End Of) Edit Dialog-->

setup step 4. Add a datatable definition in javascript with a few columns including a button in each row.

  var tasksListTable = $('#tasksTable').DataTable({
    "ajax": {
        "url": _jsURLTasksApi,
        "type": "GET",
        "dataSrc": ""
    },

    "columns": [
        { "data": "taskId" },
        { "data": "taskName" },
        {
            "data": '',
            render: (data, type, row) => {
                return `<button class="btn btn-warning jsTaskEditButton" data-recordid='${row.taskId}' >Edit</button>`;
            }
        }
    ],
    'columnDefs': [
        {
            "targets": 2, // third column - edit button
            "className": "text-center",
            "width": "10%"
        }
    ],
    "order": [[1, "asc"]],
    "processing": true,
    "language": {
        "processing": 'Loading Data .. <div class="spinner-border text-primary"></div>'
    },
    "drawCallback": function (settings, json) {
        
        $(".jsTaskEditButton").click(showEditDialog);
        
    }
});

setup step 5. add an event handler function called showEditDialog() in javascript

//Helper: show Edit function
function showEditDialog(e) {
    e.preventDefault();

    var myModal = new bootstrap.Modal($(modalElementId), {
        keyboard: false
    })
    myModal.toggle();
}//(End of) Function

Debugger code (debug.datatables.net):
Error messages shown:
no error message
Description of problem:

(execution)
Now run the program and you should see rows with an Edit button in each.

Type one or two letters in the datatable search box.

click on the "edit" button from the search result.

The edit dialog will appear but also note the presence of multiple backdrop divs just before the closing body tag (</body>).

Now, close the edit dialog and observe only one modal backdrop is removed! Since the other backdrop stays, user cannot click on anything on the page!

My Workaround:
I have done the following as a workaround in the document.ready() method of Jquery.

/Document ready
$(document).ready(function () {
    //reduce the dataTable width of all datatables so that the horizontal scrollbar does not appear unnecessarily.
    var curParentWidth = $(".dataTable").parent().width();
    $(".dataTable").width(curParentWidth - 5);

    //fix multiple modal dropdown issue
    fixMultipleModalDropdowns();
});//(End OF) document.ready

//Helper: function that attaches event handlers for modals
function fixMultipleModalDropdowns() {
    //fix issue with multiple modal backdrops overlapping - hide all backdrops as soon as the modal is shown
    $(".modal").on("show.bs.modal", function () {
        $(".modal-backdrop").hide();
    });

    //when the "show event is complete" = "shown", then we may have multiple backdrops. remove all but the first one
    $(".modal").on("shown.bs.modal", function () {
        if ($(".modal-backdrop").length > 1) {
            $(".modal-backdrop").not(':first').remove();
        }
        $(".modal-backdrop").show();
    });
}


Observe the "fixMultipleModalDropdowns()" function.
In this function I am doing 2 things:
1. when the bootstrap modal's "show" event is fired, I hide all .modal-backdrop
2. when the bootstrap modal's "shown" event is fired, i remove all but the first .modal-backdrop

the reason for hiding all the backdrops in step 1 is so that the multiple backdrops do not darken the background unnecessarily.

Replies

  • kthorngrenkthorngren Posts: 21,299Questions: 26Answers: 4,945

    The problem is with this:

        "drawCallback": function (settings, json) {
             
            $(".jsTaskEditButton").click(showEditDialog);
             
        }
    

    Each time the Datatable is drawn new event handlers will be created, adding to any that already exist, for the rows on the page. Instead use delegated events like this example.

    Kevin

  • skchandonskchandon Posts: 2Questions: 0Answers: 0
    edited May 2022

    You have pointed me to the right direction.

    It seems the issue is with the way I am doing the modal display inside the handler. Since I am using bootstrap 5 modal, I am doing the modal toggle after creating a new modal object. The creation of a new modal object every time, is causing the issue.

    Here is the current code for showing the modal - from "showEditDialog()" function:


    var myModal = new bootstrap.Modal($(modalElementId), { keyboard: false }) myModal.toggle();

    if instead, I declare a global variable to store the reference of the modal object, then the issue goes away.

    //Global var
    var _editModal = null;
    
    //Helper: show Edit function
    function showEditDialog(e) {
        e.preventDefault();
     
        if (_editModal == null)
        {        
            _editModal = new bootstrap.Modal($(modalElementId), {
                keyboard: false
            });
        }
        _editModal.toggle();
    }//(End of) Function
    

    I have tested this code after removing the workaround mentioned in my original post and it worked. I did not had to change the handler attachment code in the "drawCallback" event of the datatable.

Sign In or Register to comment.