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. A 2015 post has finally given me a clue…your code sample isn’t identical to mine, but the problem is. I have a function call to a .change when a select box is changed. Works on the first page, not on subsequent. The .on samples you have don’t work and changing to .change or .on ('change',... etc don’t work.

    Code:

    $("select#closeStatus").on('change', '.btn-details', function () {
                alert("testing");
                //$("select#closeStatus");
            });
            $("select#closeStatus").change(function () {
    ...
    

    Thoughts? What am I missing?

    1. Please use the following pattern:

      $(tableSelector).on('change', elementSelector, function(e){
         // Your code here
      });
      

      Using id attribute closeStatus for more than one select element is not recommended, you need to use class instead.

      For example, for table with ID example and multiple select elements with class closeStatus:

      $('#example').on('change', 'select.closeStatus', function(e){
         // Your code here
      });
      
  2. My problem was similar to @Chad M and your answer worked for me. Thank you so much @Michael Ryvkin !

  3. This is the most concise, succinct discussion/answer to this problem that I’ve ever seen. Thanks! DataTables in general and pagination in particular has caused me countless hours of frustration.

      1. I wonder if you have an answer to the issue of pagination on (for instance) page 4 jumping back to page 1 when some a checkbox is clicked (and thus the form is submitted). I’ve seen the “stateSave: true” thing but that causes it to **always** be on whatever page it’s on, even when I go to another part of the site and then come back. Just asking, so I appreciate any insight you can provide.

  4. Hello Micheal,

    Very clean code you’ve got here.
    I have a scenario where the data for the table is generated from a database in a .Net core environment. What i need is implement the EDIT or DETAILS button to display records in a modal popup on clicking the button on a row.

    I pull data via a controller action. It works very well when i use normal tables in a Razor form. Trying to get a good example using jQuery datatables.

    Would really appreciate if you could help with this.

    Regards,

    George.

    1. ..Again Micheal,

      To buttress my question, i load data with an Ajax call to display tabular records in Datatables. I see the records you have in the example above were pre-filled..

      Hope to hear from you soonest.

      Regards…

      George

  5. Your working example doesn’t seem to be working on Firefox or Chrome? Has something changed? Might be time to update this article.

    Regards,

    George Geschwend

  6. I take my comment back! It works on BOTH examples if you are talking about the Edit button on each row. I was able to fiddle with the rows and the popup menu appears in both your working example and the non-working example.

      1. Michael — 

        I clicked on the JS Fiddle link above  the first non working example… and it looks like the code is

        $(‘#example’).on(‘click’, ‘.btn-edit’, function(){//looked like the working code you described.

              // Reset form

              $(‘#form-edit’).get(0).reset();

              // Store current row

              $(‘#modal-edit’).data(‘row’, $(this).closest(‘tr’));

              // Show dialog

              $(‘#modal-edit’).modal(‘show’);

           });

        I then replaced the $(‘#example’).on(‘click’, ‘.btn-edit’, function(){

        with:

        $(‘#example .btn-edit’).on(‘click’, function(){

        ..and saved it in fiddle.

        I then returned to the web-page… and when I went to the 1st example the on-click function  went to the second page of the table, and it behaved as you described in the problem statement.

        I returned the code to what you had. I am not that familiar with JSFiddle… so my guess is… that’s the working code is some how linked to your first pre-fix example. Maybe my meds aren’t working today and I am hallucinating …. dunno …please excuse me if I am. 🙂

        George

        1. George, you’re absolutely right! The first example demonstrating the problem already had corrected code, not sure how’s that happened. Thank you for spotting the issue!

          I updated the non-working example code to use the $(‘#example .btn-edit’).on(‘click’, function(){ to demonstrate the problem.

Leave a Reply

(optional)

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