jQuery DataTables: Why click event handler does not work

This is one of the most common problems users have with jQuery DataTables plug-in and it has very simple solution if you understand why it occurs.

Problem

Table below demonstrates the problem with attaching event handlers incorrectly. Clicking on “Edit” button should open a modal dialog.

Event handler is attached as follows:


$('#example .btn-edit').on('click', function(){
   // ...
});

However if you go to a different page, sort or filter the table, “Edit” button stops working for those records that were previously hidden.

Cause

After the table is initialized, only visible rows exist in Document Object Model (DOM). According to jQuery on() documentation:

Event handlers are bound only to the currently selected elements; they must exist at the time your code makes the call to .on()

Our code above worked only for the first page elements because elements from other pages were not available in DOM at the time the code was executed.

Solution

The solution is to use event delegation by providing selector for target element as a second argument in on() call, see example below. According to jQuery on() documentation:

Delegated events have the advantage that they can process events from descendant elements that are added to the document at a later time.


$('#example').on('click', '.btn-edit', function(){
   // ...
});

We attach event handler to the table '#example' and specify a selector for the button '.btn-edit' as an additional parameter for on() method. Event handler will now be called for all buttons whether they exist in DOM now or added at a later time.

Table below demonstrates the working solution.

You May Also Like

Comments

  1. Thanks Michael,

    Are you able to get this solution to work if you have column searching enable? Everything in your example works great until I enable the column sorting options. When the grid initially renders everything works fine, however once I filter a specific column by some text I have to click twice to invoke the on click event.

    Thanks,

    1. Wade, I can’t replicate the behavior you’re talking about. For example, I search for “Accountant”, there are two records shown. Click on “Edit” button works as expected, only one click is required.

      1. I’m also getting this issue.
        Michael is correct that it doesn’t affect the default searching abilities (searching all columns) but it affects the individual column filtering. It’s strange, after the second click it fires the listener…

          1. Originally datatables suggested binding both a keyup and onchange (for mouse copy and pastes) event handlers to the search filter text input.

            // Old doc with issue.
            $('<input type="text").on('keyup change', function () {
                    column.search(this.value).draw();
            });
            
            //Which has now been replaced with
            $('<input type="text").keyup(function () {
                    column.search(this.value).draw();
            });
            

            I see your solution still uses the keyup which got me intrigued…

            Turns out when I was clicking the button the onchange for the input was firing and redrawing the table instead of the button on click. On the second click of the button the event handler would finally fire.

            This line in your code prevents this, if you remove it you'll get the same issue:
            if ( that.search() !== this.value ) {

            https://jsfiddle.net/cm03xyfr/1/

            I would have thought both the input change and button click would have fired? Very strange…

            1. Got it… so the change event fires first, redrawing the table… then the click on the table attempts to fire but of course there’s no buttons as the table is being redrawn at that point…
              Thanks for your help!

  2. Hi, Thank you so much, this resolved my problem to get click event on other pages but now i am not able to get data which i used to get when i was using on click event, please suggest how to get row data in this case, please find my old code and new code.

    OLD

    $(".add-access").click(addaccessEvent);
    function addaccessEvent() {
       var allData = table.rows($(this).parents('tr')).data();
    }
    

    NEW CODE

    $('#dataFound').on('click', '.add-access','tr', function () {
       addaccessEvent();                    
    }); 
    
  3. It is a good control to work with if we have requirement to open single datatable popup but become complicated and error full when open second datatable popup on the same page,doing paging on second data table but the data for first data table change, sorting second data table but the data for first data table sorts sometime getting popup message that datatable not initialized but resolved by using “bDestroy”:true but still paging is creating lots of problem. Please anyone can help in this if similar situation has occured or has been resolved by any one of you?

  4. Just going to add to the chorus of praise that this tip has gathered. Saved me from refactoring DataTables out of our project!

  5. I have same problem here but I’m really confused how to solve this problem

    $(document).ready(function () {
       $(".open_modal").click(function(e) {
          var m = $(this).attr("id");
           $.ajax({
                 url: "modal-edit-spc.php",
                 type: "GET",
                 data : {id: m,},
                 success: function (ajaxData){
                   $("#ModalEdit").html(ajaxData);
                   $("#ModalEdit").modal('show',{backdrop: 'true'});
                 }
          });
       });
    });
    
    1. If open_modal is a link in the table and example is your table ID, attach event handler as follows:

      $("#example").on("click", ".open_modal", function(e){
         // ... your code ...
      });
      
  6. Thank you so much. I saw other answers that I think were saying the same thing, but did turn the light bulb on for me.
    Your example did the trick. Now I am back to find the next issue. Happy coding and thanks again.

Leave a Reply

(optional)

This site uses Akismet to reduce spam. Learn how your comment data is processed.