DataTables break on last “Next” or any “Previous”

2019-08-03 17:36发布

问题:

I have the following DataTable which calls status_icons() function for replacing 0 & 1 values with icons.

At first results page (on initComplete) I call status_icons() for the replacement and then I make a trigger out of DataTables scope in order to have my function re-executed for next paginated results due to DataTable DOM reconstruction behavor for each pagination.

The error I get is that re-adds the status icons over the current ones when you you click on the "Previous" button on any pagination or the numbered pagination boxes.

My function for replacing values with icons

function status_icons() {

    $('table tr').each(function() {
        if ($(this).find('td').eq(0).text() == '1') {
            $(this).find('td').eq(0).replaceWith('<i class="fa fa-3 fa-check-circle-o datatable-paid-1"></i>');
        } else {
            $(this).find('td').eq(0).replaceWith('<i class="fa fa-3 fa-exclamation-circle datatable-paid-0"></i>');
        }
    });
}

DataTable construction - on initComplete calls the function for the first and second page results

setTimeout(function() {
  $('#invoices-table').DataTable({
    responsive: true,
    columnDefs: [{ orderable: false, targets: [-1, -2, -3] }],
    dom: 'Bfrtip',  
    initComplete: function() {
      status_icons() // it executes my function for the first page of results
      var api = this.api();
      // some irrelevant code that uses api and does not cause my issue
      // ...

    }
  });
}, 1000);

jQuery event for executing my function each time a .paginate_button is clicked due to DataTable reconstruction

$(document).on('click','.paginate_button', function() {
  if( !$(this).hasClass("disabled") ){
    status_icons(); // it executes for the rest paginations
  }
});

https://codepen.io/anon/pen/Wjqbbd

回答1:

In general it is a really bad thing to delegate events to the document object. Furthermore, dataTables steals the click event totally, preventing you from adding additionally click event handlers to .paginate_buttons. A working event handler on a .paginate_button would be

$('body').on('mousedown','.paginate_button', function() {
  ...
})

However, your approach is somehow exaggerated or "wrong" in the context of what you want to achieve. dataTables have a columns.render callback to deal with exact those issues. Simply add this to your columDefs section :

columnDefs: [
  { orderable: false, targets: [-1, -2, -3] },
  { targets : 0, 
    render: function(data, type) {
      if (type == 'display') {
        return data == '1' 
          ? '<i class="fa fa-3 fa-check-circle-o datatable-paid-1"></i>'
          : '<i class="fa fa-3 fa-exclamation-circle datatable-paid-0"></i>'
      } else {
        return data
      }
    }
  }
],

And you are good. It solves both problems: The one with lack of action on click, you dont have to worry on page changes at all - and the one with replicated font awesome icons inserted over and over.

It simply works by returning the correct <i> font awesome markup when dataTables want to display content for the column.

Have ported your code to a jsfiddle -> http://jsfiddle.net/2tzp19se/



回答2:

Just use .html() instead of .replaceWith().

.replaceWith() does not only replace the td content...
But replaces the td itself with the passed argument (string or object).

Updated CodePen