Checkboxes not working in DataTables after server-side processing

Viewed 814

I have a DataTable that loads its rows using server-side processing and Ajax. Each row has a checkbox containing a numerical ID as the value.

<input class="form-check-input" type="checkbox" id="coupon-111" name="chk[]" value="111">

There is a button outside of the table that performs an action to those rows that are checked - in this case changing an entry from Active to Inactive. When the button is clicked, it runs this script:

$(document).on('click', 'button[data-action]', function () {

    var action = $(this).data('action');  //Gets the action from the button clicked "Active" / "Inactive"
    var selected = [];  // Starts empty array of IDs for the rows checked.

    // If the checkbox is checked, push its value (111) to the array.
    $('td.check input:checked').each(function(i, e) {
        selected.push($(this).val());
    });

    console.log(selected); // Console shows an empty array "[]" 

    // ...

});

Before adding server-side processing and ajax, this featured worked fine. I know its something to do with the Ajax loading the results dynamically. If this were an event, I would just bind it to $(document) like I did with the button. How can I get this to work with .each() (or what should I do differently)?

Here is the DataTables JS and Ajax:

jQuery(document).ready(function() {
    
    var table = jQuery('#coupons-list').dataTable({
        'pageLength': 25,
        'autoWidth': false,
        'bProcessing': true,
        'sAjaxSource': './list.php',
        'bPaginate': true,
        'sPaginationType': 'full_numbers',
        'iDisplayLength': 5,
        'oLanguage': {
            'sProcessing': '<div class="loader"><i class="fad fa-spinner-third fa-spin" aria-hidden="true"></i></div>'
        },
        'aoColumns': [
            { mData: 'check' },
            { mData: 'status' },
            { mData: 'code' },
            { mData: 'assigned_to' },
            { mData: 'discount_value' },
            { mData: 'start_date' },
            { mData: 'end_date' },
            { mData: 'uses_left' }
        ],
        'createdRow': function(row, data, dataIndex) {
            $(row).addClass('click-row').attr('data-href', './view/?id='+data['id']);
        }
    });

});

list.php:

$coupons_list = array();
$select = $db -> prepare("SELECT coupons.id, coupons.influencer_id, coupons.status, coupons.code, coupons.value, coupons.type, coupons.start_date, coupons.end_date, coupons.uses_left, users.fname, users.lname FROM coupons LEFT OUTER JOIN influencers ON influencers.id = coupons.influencer_id LEFT OUTER JOIN users ON users.id = influencers.user_id ORDER BY coupons.code ASC");
$select -> execute();
$select -> bind_result($coupon_id, $influencer_id, $coupon_status, $coupon_code, $coupon_value, $coupon_type, $coupon_start_date, $coupon_end_date, $coupon_uses_left, $user_fname, $user_lname);
while ($select -> fetch())
{
    $coupon = array(
        'check' => '<input class="form-check-input" type="checkbox" id="coupon-'.$coupon_id.'" name="chk[]" value="'.$coupon_id.'">',
        'id' => $coupon_id,
        'status' => $coupon_status,
        'code' => $coupon_code,
        'assigned_to' => $coupon_influencer,
        'discount_value' => number_format($coupon_value, 2),
        'start_date' => $coupon_start_date,
        'end_date' => $coupon_end_date,
        'uses_left' => $coupon_uses_left
    );
    array_push($coupons_list, $coupon);
}

$table_data = array(
    'sEcho' => 1,
    'iTotalRecords' => count($coupons_list),
    'iTotalDisplayRecords' => count($coupons_list),
    'aaData' => $coupons_list
);

echo json_encode($table_data);
1 Answers

With the help of @andrewjames I was able to figure out the problem.

Your click function expects each checkbox to have a class called check: 'td.check input:checked' - how is that class added?

I used DataTables' columnDefs to add the "check" class to the <td>, as well as another "no-click" class. Problem was, that the second class overwrites the first.

'columnDefs': [
    { className: 'check', targets: 0 },
    { className: 'no-click', targets: 0 },  // Overwrites "check"
    { className: 'fixed', targets: 1 }
]

So instead, I did it like this to make it work as intended:

'columnDefs': [
    { className: 'check no-click', targets: 0 },
    { className: 'fixed', targets: 1 }
]
Related