How to make a row read-only based on value from another column in the table?

How to make a row read-only based on value from another column in the table?

RAWaddellRAWaddell Posts: 42Questions: 5Answers: 0

I'm using DT for the first time and have it working pretty well, but one thing my Google-fu is failing at is finding a way to dynamically make a row read-only (i.e. my checkbox selector (multi) in Column 0 cannot be checked) based on the value of another column in the table.

$(document).ready(function() {

    $('#show-entries').DataTable( {
        "language": {
            "search": "Filter records:"
        },
        columns: [
           { data: null, title: "Select"},
           { data: "ID", title: "ID" },
           { data: "Year", title: "Year" },
           { data: "First_Name", title: "First_Name" },
           { data: "Last_Name", title: "Last_Name" },
           { data: "Entry_Form_Number", title: "Entry #" },
           { data: "Barcode_Text", title: "Barcode" },
           { data: "Entrant_Name", title: "Entrant Name" },
           { data: "Model_Name", title: "Title of Entry" },
           { data: "Category_Name", title: "Category" },
           { data: "Paid", title: "Paid" ,
             render: function (data, type, row, meta) {
               if (type === 'display') { 
                 return data === "1" ? 'Y' : 'N';
               }
               return data;
              }
           },
           { data: "DatePaid", title: "Date Paid" },
           { data: "DateCreated", title: "Date Created" },
           { data: null, title: "Print",
             render: function (data, type, row, meta) {
                return '<input type="button" class="btn-print printrec" id="' + meta.row + '" value="Print"/>';
             }
           }
         ],
        "columnDefs": [ 
            {
                defaultContent: '',
                orderable: false,
                className: 'select-checkbox',
                targets:   0
            },
            { className: "dt-center", "targets": [ 10 ] },
            {
                 // Hide 'ID' & 'Year' columns
                "targets": [ 1, 2 ],
                "visible": false,
                "searchable": false
             },
             {
                 // Hide 'First_Name' & 'Last_Name' columns
                "targets": [ 3, 4 ],
                "visible": false
             },
             {
                 // Limit 'Entrant Name' text length
                "targets": [ 7 ],
                render: function ( data, type, row ) {
                    return type === 'display' && data.length > 43 ?
                        data.substr( 0, 43 ) +'…' :
                        data;       
                }
             },
             {
                 // Limit 'Title of Entry' text length
                "targets": [ 8 ],
                render: function ( data, type, row ) {
                    return type === 'display' && data.length > 100 ?
                        data.substr( 0, 97 ) +'…' :
                        data;       
                }
             }
        ],
        select: {
            style: 'multi',
            selector: 'td:first-child',
            info: true
        },
        order: [[ 1, 'asc' ]]
     } );

    $('#formsearch').click(function() {
        // Get values of search inputs
        var  contestYear= $('#contest-year').val();
        var  entryNumber= $('#entry-number').val();
        var  barCode= $('#barcode').val();
        var  firstName= $('#first-name').val();
        var  lastName= $('#last-name').val();
        var  title= $('#title-name').val();
        var  isPaid = $('input[name=paidStatus]:checked').val();

        // Send Ajax request to get results of search entry
        $.ajax({
            type: "POST",
            url: "php/searchreceive.php",
            data:{"c_year": contestYear, "e_number": entryNumber, "bCode":barCode, "fName":firstName, "lName": lastName, "title":title, "isPaid":isPaid} 

        }).done(function(status) {
            status=status.trim();
            if(status==="InvalidSession"){
                // Redirect to logout page
                window.location.href='../common/php/logout.php';
            }
            if(status==="NoResults") {
                alert("No records found - please try again.");
            }else {
                // Process result data into DT
                dataSet = JSON.parse(status);
                //console.log(dataSet);
                
                // clear table and add new rows
                $('#show-entries').DataTable().clear().draw();
                $('#show-entries').DataTable().rows.add(dataSet).draw();                

            }
        }); 
    });

    // Select All button 
    $('#selectAll').click(function() {
        if(this.checked) {
            //checked here
            $('#show-entries').DataTable().rows().select();
            //console.log('selectall checked');
        }
        else {
            //unchecked here
            $('#show-entries').DataTable().rows().deselect();
            //console.log('selectall unchecked');
        }
    });     
});

The column titled 'Select' is a DT checkbox and what I'd like to do is make a row read-only if the 'Paid' column is 'Y', so that the $selectAll click event (tied to a checkbox outside of DT) will not update that row (Ultimately, what will happen is the user will use my main HTML form to do a search and then use the 'selectAll' button to select all non-Paid rows in the table; that list of selected rows will then be passed to a PHP script for processing). I think I need a render function inside 'Select', but how to I make it dynamic based on what's in 'Paid' for that row?

This question has accepted answers - jump to:

Answers

  • RAWaddellRAWaddell Posts: 42Questions: 5Answers: 0

    Perhaps ‘read-only’ is the wrong term - disabled, maybe? A callback function in the column render?

  • kthorngrenkthorngren Posts: 21,469Questions: 26Answers: 4,977

    The easiest thing to do would be to remove the select-checkbox class from the column. The checkbox wouldn't show. That you would probably do in rowCallback.

    Haven't tried this but you might be able to use the select handler to check the data in the row and deselect if needed. The first example shows how to get the data using pluck() which is what you would do then use row().deselect() if appropriate.

    Kevin

  • RAWaddellRAWaddell Posts: 42Questions: 5Answers: 0

    Thanks Kevin, but is there a way to do this before a user tries to select the row? In other words, make the checkbox read-only/disabled on the first draw after processing the results from the Ajax call if the value of 'Paid' = 'Y'?

  • kthorngrenkthorngren Posts: 21,469Questions: 26Answers: 4,977
    Answer ✓

    I was going to mention that I missed a step with option one. In your select option config you would change the selector to the select-checkbox class:
    selector: '.select-checkbox',

    A better option would be to do as you mention, to disable the checkbox. I think the easiest way to do this is to add a second class to column 0, select-enabled for example then set the selector to that. For example:

            "columnDefs": [
                {
                    defaultContent: '',
                    orderable: false,
                    className: 'select-checkbox select-enabled',
                    targets:   0
                },
    ....
            select: {
                style: 'multi',
                selector: 'select-enabled',
                info: true
            },
    
    

    Then in rowCallback you can add or remove the class as desired. Updated example:
    http://live.datatables.net/vinipiye/4/edit

    Note that I'm checking to see if Paid == "1" because that is the original data as the render function is only updating the displayed data.

    Kevin

  • RAWaddellRAWaddell Posts: 42Questions: 5Answers: 0

    While you were typing your answer, I added this:

            "rowCallback": function( row, data, index ) {
                if ( data.Paid === "Y" ) {
                    $('td:first-child', row).removeClass('select-checkbox');                
                }
            },
    

    ... which didn't work. Then I saw your most recent post and changed the check on Paid to "1" and bingo - the checkbox for those rows disappears! Thanks again!

  • RAWaddellRAWaddell Posts: 42Questions: 5Answers: 0

    Spoke too soon. So, the checkbox disappears for those rows where Paid=1, but I can still select the row via:

        // Select All button 
        $('#selectAll').click(function() {
            if(this.checked) {
                //checked here
                $('#show-entries').DataTable().rows().select();
                //console.log('selectall checked');
            }
            else {
                //unchecked here
                $('#show-entries').DataTable().rows().deselect();
                //console.log('selectall unchecked');
            }
        }); 
    

    So, I still need to disable the row to prevent it from being selected.

  • kthorngrenkthorngren Posts: 21,469Questions: 26Answers: 4,977
    edited March 2018

    If you use the second class then you can also use that as the row selector:
    https://datatables.net/reference/type/row-selector

    I think this should work using the additional .select-enabled class:
    $('#show-entries').DataTable().rows('.select-enabled').select();

    Kevin

  • RAWaddellRAWaddell Posts: 42Questions: 5Answers: 0

    I tried your code from your site but all checkboxes are disabled (regardless if Paid = 1 or not). But, if I click my 'Select all' button it still selects all the rows.

    function get(path, parameters) {
        // GET to the provided URL with the specified parameters.
        var form = $('<form></form>');
    
        form.attr("method", "get");
        form.attr("action", path);
    
        $.each(parameters, function(key, value) {
            var field = $('<input></input>');
    
            field.attr("type", "hidden");
            field.attr("name", key);
            field.attr("value", value);
    
            form.append(field);
        });
    
        // The form needs to be a part of the document in
        // order for us to be able to submit it.
        $(document.body).append(form);
        form.submit();
    }
    
    $(document).ready(function() {
    
        $('#show-entries').DataTable( {
            "language": {
                "search": "Filter records:"
            },
            columns: [
               { data: null, title: "Select",
                    defaultContent: ''},
               { data: "ID", title: "ID" },
               { data: "Year", title: "Year" },
               { data: "First_Name", title: "First_Name" },
               { data: "Last_Name", title: "Last_Name" },
               { data: "Entry_Form_Number", title: "Entry #" },
               { data: "Barcode_Text", title: "Barcode" },
               { data: "Entrant_Name", title: "Entrant Name" },
               { data: "Model_Name", title: "Title of Entry" },
               { data: "Category_Name", title: "Category" },
               { data: "Paid", title: "Paid" ,
                 render: function (data, type, row, meta) {
                   if (type === 'display') { 
                     return data === "1" ? 'Y' : 'N';
                   }
                   return data;
                  }
               },
               { data: "DatePaid", title: "Date Paid" },
               { data: "DateCreated", title: "Date Created" },
               { data: null, title: "Print",
                 render: function (data, type, row, meta) {
                    return '<input type="button" class="btn-print printrec" id="' + meta.row + '" value="Print"/>';
                 }
               }
             ],
            "columnDefs": [ 
                {
                    defaultContent: '',
                    orderable: false,
                    className: 'select-checkbox select-enabled',
                    targets:   0
                },
                { className: "dt-center", "targets": [ 10 ] },
                {
                     // Hide 'ID' & 'Year' columns
                    "targets": [ 1, 2 ],
                    "visible": false,
                    "searchable": false
                 },
                 {
                     // Hide 'First_Name' & 'Last_Name' columns
                    "targets": [ 3, 4 ],
                    "visible": false
                 },
                 {
                     // Limit 'Entrant Name' text length
                    "targets": [ 7 ],
                    render: function ( data, type, row ) {
                        return type === 'display' && data.length > 43 ?
                            data.substr( 0, 43 ) +'…' :
                            data;       
                    }
                 },
                 {
                     // Limit 'Title of Entry' text length
                    "targets": [ 8 ],
                    render: function ( data, type, row ) {
                        return type === 'display' && data.length > 100 ?
                            data.substr( 0, 97 ) +'…' :
                            data;       
                    }
                 }
            ],
            select: {
                style: 'multi',
                selector: 'select-enabled',
                info: true
            },
            
            rowCallback: function(row, data, index) {
                if ( data.Paid === "1" ) {
                    $('td:first-child', row).removeClass( 'select-enabled' );
                } else {
                    $('td:first-child', row).addClass( 'select-enabled' );
                }
            },
            
            
            order: [[ 1, 'asc' ]]
         } );
    
        $('#formsearch').click(function() {
            // Get values of search inputs
            var  contestYear= $('#contest-year').val();
            var  entryNumber= $('#entry-number').val();
            var  barCode= $('#barcode').val();
            var  firstName= $('#first-name').val();
            var  lastName= $('#last-name').val();
            var  title= $('#title-name').val();
            var  isPaid = $('input[name=paidStatus]:checked').val();
    
            // Send Ajax request to get results of search entry
            $.ajax({
                type: "POST",
                url: "php/searchreceive.php",
                data:{"c_year": contestYear, "e_number": entryNumber, "bCode":barCode, "fName":firstName, "lName": lastName, "title":title, "isPaid":isPaid} 
    
            }).done(function(status) {
                status=status.trim();
                if(status==="InvalidSession"){
                    // Redirect to logout page
                    window.location.href='../common/php/logout.php';
                }
                if(status==="NoResults") {
                    alert("No records found - please try again.");
                }else {
                    // Process result data into DT
                    dataSet = JSON.parse(status);
                    //console.log(dataSet);
                    
                    // clear table and add new rows
                    $('#show-entries').DataTable().clear().draw();
                    $('#show-entries').DataTable().rows.add(dataSet).draw();                
    
                }
            }); 
        });
    
        $('#show-entries tbody').on('click', '.printrec', function () {
    
            // Need to get specific column data as before and then call
            // GET function at the top of this file
    
            var id = $(this).attr("id");
            var data = $('#show-entries').DataTable().row( id ).data();
            
            // dumps all data
            // console.log($('#show-entries').DataTable().row( id ).data());
            
            // dumps specific column data
            //console.log(data.ID, data.Year, data.Entry_Form_Number, data.First_Name, data.Last_Name);
    
            // Call custom 'get' function (top of page)
            get('php/openPDFprintout.php', {"p1": data.ID, "p2": data.Year, "p3": data.Entry_Form_Number, "p4": data.First_Name, "p5": data.Last_Name});
    
        });
        
        // Reset all data
        $('#formreset').click(function() {
            //console.log('Reset button clicked');
            // Clear table
            $('#show-entries').DataTable().clear().draw();
        });
        
        // Select All button 
        $('#selectAll').click(function() {
            if(this.checked) {
                //checked here
                $('#show-entries').DataTable().rows().select();
                //console.log('selectall checked');
            }
            else {
                //unchecked here
                $('#show-entries').DataTable().rows().deselect();
                //console.log('selectall unchecked');
            }
        });     
        
        // Procees selected records as paid button click
        $('#processAsPaid').click(function() {
            // Get db IDs of selected rows
            console.log('Process Checked as Paid button clicked');
            
            var dtTable = $('show-entries').DataTable();       
            dtTable.rows().every( function ( rowIdx, tableLoop, rowLoop ) {
                //console.log('rowIdx:', rowIdx);
                var data = this.data();
                console.log('ID:' + data.ID);
            } );        
            
    
            var data = dtTable.rows().data();
            data.each(function (value, index) {
                console.log('Data in index: ' + index + ' is: ' + value);
            });
    
            dtTable.rows().every(function(){
                console.log('this.data' + this.data());
            });
        });    
    });
    
  • kthorngrenkthorngren Posts: 21,469Questions: 26Answers: 4,977

    Not sure why all your checkboxes would be disabled, don't see anything that stands out in your code. It looks the same as mine and mine seems to work.

    Yep, I can see that my guess at the selector for select all isn't correct. According to the docs you should be able to select rows based on td node info but I haven't figured out what to use. I tried a couple things in my example. Maybe someone else can help or if I find something I will respond.

    Kevin

  • kthorngrenkthorngren Posts: 21,469Questions: 26Answers: 4,977

    I was able to use a function to select the rows with the class select-enabled:

            if(this.checked) {
                //checked here
                $('#show-entries').DataTable().rows(function ( idx, data, node ) {
                    return $(node).find('td:first-child').hasClass('select-enabled');
                  } ).select();
                //console.log('selectall checked');
            }
    

    Its working here:
    http://live.datatables.net/vinipiye/4/edit

    Kevin

  • RAWaddellRAWaddell Posts: 42Questions: 5Answers: 0

    Thanks Kevin. It's working great, except for records not on the current page - clicking the 'Select all' button will select Paid rows not on the current page, but if you go to that page and toggle the 'Select all' button then it won't select them.

  • kthorngrenkthorngren Posts: 21,469Questions: 26Answers: 4,977
    Answer ✓

    Sorry, I thought rowCallback affected all rows but it only runs on the displayed rows. You will need to use columns.createdCell for column 0 to do this. You can remove the rowCallback and do something like this:

                 {defaultContent: '',
                    orderable: false,
                    className: 'select-checkbox select-enabled',
                    targets:   0,
                    createdCell: function (td, cellData, rowData, row, col) {
                      if ( rowData.Paid == 1 ) {
                        $(td).removeClass( 'select-enabled' );
                      } else {
                        $(td).addClass( 'select-enabled' );
                      }
                    }
                },
    

    You can see the working example here:
    http://live.datatables.net/vinipiye/4/edit

    There are now two pages of display.

    Kevin

  • RAWaddellRAWaddell Posts: 42Questions: 5Answers: 0

    That's it! Thank you very much.

This discussion has been closed.