Row selection and deselection problem

Row selection and deselection problem

Stacey1134Stacey1134 Posts: 112Questions: 20Answers: 0

Hey all, I am having a problem. When my user selects a datatables row, it populates variables (in external quill instances and such). If the user selects another row it will overwrite the variables. I have set up a confirm box, to prompt the user. The problem is once cancel is pressed, the new record is still highlighted. If I do this 3 times, two records are highlighted even when my select is set to single. Any suggestions? Here is relevant code:

    <script>
        var editor; // use a global for the submit and return data rendering in the examples
        var savedFirst; // prevents user from sending to printer unless document is saved

        $(document).ready(function() {
            var table2 = $('#editTable').DataTable({
                pageLength: 5,
                lengthMenu: [[5, 10, 20, -1], [5, 10, 20, 'All']],
                ajax: 'ajaxPhoneLogs.php',
                processing: true,
                language: {
                    processing: '<i class="fa-duotone fa-gear fa-spin"></i> Data Loading...',
                    searchBuilder: {
                        button: '<i class="fa-solid fa-magnifying-glass-arrow-right"></i> Refine Search',
                        title: 'Choose Filter Options'
                    }
                },
                buttons: [
                    '<i class="fa-solid fa-magnifying-glass-arrow-right"></i> Refine Search'
                ],
                columns: [
                    { data: 'phonelogs.id', visible: false, searchable: false },
                    { data: 'phonelogs.CR_ID', visible: false },
                    { data: "phonelogs.callDateTime", render: DataTable.render.datetime('M/D/YYYY, h:mm:ss a') },
                    { data: 'calltypes.name' },
                    {
                        data: null, render: function (data, type, row) {
                            return data.form.FirstName + ' ' + data.form.LastName;
                        }, searchable: false
                    },
                    { data: "phonelogs.callNotes", visible: false },
                    { data: "phonelogs.greeting", visible: false, searchable: false },
                    { data: "phonelogs.poled1", visible: false, searchable: false },
                    { data: "phonelogs.poled2", visible: false, searchable: false },
                    { data: "phonelogs.responseBody", visible: false, searchable: false },
                    { data: "phonelogs.closing", visible: false, searchable: false },
                    { data: "phonelogs.answeredBy", visible: false },
                    { data: 'PrisonFacilityListing.Prison_Name' },
                    {
                        data: "phonelogs.printed", searchable: false,
                        render: function (val, type, row) {
                            return val == 0 ? "No" : "Yes";
                        }, searchable: false
                    },
                    { data: "form.FirstName", visible: false },
                    { data: "form.LastName", visible: false },
                    { data: "form.PrisonerID", visible: false }
                ],
                select: 'single',
                order: [2, 'desc'],
            });

            var previousLog = null; // To store previous data
            var previousSelectedRow = null; // To store the previously selected row

            function isDifferentLog(log1, log2) {
                return JSON.stringify(log1) !== JSON.stringify(log2);
            }

            $('#editTable tbody').on('click', 'tr', function () {
                var newLog = table2.row(this).data();
                var currentRow = this;                
                console.log('New log selected:', newLog);

                // Check if there is previous data and the user is trying to select a new row
                if (previousLog && isDifferentLog(previousLog, newLog)) {
                    var userConfirmed = confirm("You have unsaved changes. Do you want to overwrite the previous response?");
                    if (!userConfirmed) {
                        // Deselect the new row immediately
                        $(currentRow).removeClass('selected');
                        
                        // Re-select the previous row if it exists
                        if (previousSelectedRow) {
                            $(previousSelectedRow).addClass('selected');
                        }
                        return; // Exit if the user does not confirm
                    }
                }

                // Clear previous selection
                table2.$('tr.selected').removeClass('selected');

                // Proceed with updating the data if the user confirms or there is no previous data
                $(currentRow).addClass('selected');
                previousLog = newLog; // Update the previous data with the new data
                previousSelectedRow = currentRow; // Store the current row as the previously selected row

I tried this but then I couldn't even half select the rows:

var previousLog = null; // To store previous data
var previousSelectedRow = null; // To store the previously selected row

function isDifferentLog(log1, log2) {
    return JSON.stringify(log1) !== JSON.stringify(log2);
}

$('#editTable tbody').on('click', 'tr', function () {
    var newLog = table2.row(this).data();
    var currentRow = this;
    console.log('New log selected:', newLog);

    // Check if there is previous data and the user is trying to select a new row
    if (previousLog && isDifferentLog(previousLog, newLog)) {
        var userConfirmed = confirm("You have unsaved changes. Do you want to overwrite the previous response?");
        if (!userConfirmed) {
            // Re-select the previous row and deselect the new row
            table2.rows().deselect(); // Deselect all rows
            if (previousSelectedRow) {
                table2.row(previousSelectedRow).select(); // Re-select the previous row
            }
            return; // Exit if the user does not confirm
        }
    }

    // Clear previous selection
    table2.rows().deselect();

    // Proceed with updating the data if the user confirms or there is no previous data
    table2.row(currentRow).select();
    previousLog = newLog; // Update the previous data with the new data
    previousSelectedRow = currentRow; // Store the current row as the previously selected row
});

Thanks in advance.. I can't set up a live test, but I can give you Allan access again if it is more than a simple mistake on my part.

This question has accepted answers - jump to:

Answers

  • kthorngrenkthorngren Posts: 21,336Questions: 26Answers: 4,951
    edited June 4

    If I do this 3 times, two records are highlighted even when my select is set to single.

    You have the wrong syntax. Use the select.style option to set single select, like this:

        select: {
            style: 'single'
        }
    

    In line 70 and 81 of your first snippet you are using something like this:

    $(currentRow).removeClass('selected');
    

    Removing the selected class doesn't deselect the row. Not sure if that is the intention.

    I built a simple test case for you.
    https://live.datatables.net/notiwaka/1/edit

    I added e as the parameter into the event handler:

    $('#example tbody').on('click', 'tr', function (e) {
    

    Then used e.stopPropagation(); instead of return to stop the click row selection. If I understand what you want to do you don't need to use row().select() or rows().deselect() in the event handler. Let Datatables select the click row unless the user cancels and there is a previously selected row. In this case stop propagation so the Datatables doesn't select the row. Otherwise if the user cancels but no row is selected the click row will be selected by Datatables.

    I used select: true so you can see that only one row is selected.

    Is this what you are looking for?

    Kevin

  • Stacey1134Stacey1134 Posts: 112Questions: 20Answers: 0

    The test case isn't working as described, and the code isn't working on my script either....But I get where you are coming from. I will see if I can get it working and post. As of now, the code in the test case , the user confirmation doesn't activate when they user selects the next a new row, just allows it, but it prevents any use of the data in the row.

    Working on it at 5:30AM my time LOL.

  • kthorngrenkthorngren Posts: 21,336Questions: 26Answers: 4,951
    Answer ✓

    Ok, so if I understand correctly maybe this is more inline of what you want:
    https://live.datatables.net/notiwaka/2/edit

    First it stops propagation so Datatables never selects the row. Leaves it up to the event handler to perform the row selection. This way two different functions aren't trying to select the rows..

    It immediately selects the clicked row. A short setTimeout function is used to allow the UI to update before the rest of the function executes. If cancelled then the previous row is selected.

    Also set the select.style to single.

    Is this more along the lines of what you are wanting?

    Kevin

  • Stacey1134Stacey1134 Posts: 112Questions: 20Answers: 0

    Unfortunately, yes and no. Evidently stopPropagation doesn't work as described either. While the setTimeout fixes my select problem for the most part, the data from the newly selected row is still loaded even before the user has a chance to confirm. For example, I made the following modifications, to trap the data load, stopPropegation doesn't halt it.

                $('#editTable tbody').on('click', 'tr', function (e) {
                    var newLog = table2.row(this).data();
                    var currentRow = this;   
                    e.stopPropagation();
    
                    setTimeout(() => {
                        // Check if there is previous data and the user is trying to select a new row
                        if ( true ) {
                            if(previousSelectedRow) {
                                var userConfirmed = confirm("You have unsaved changes. Do you want to overwrite the previous response?");
                                if (!userConfirmed) {
                                    console.log('cancel', previousSelectedRow);
                                    table2.row( previousSelectedRow ).select();
                                    data = previousLog;
                                }else{
                                    console.log('current row', currentRow)
                                    table2.row( currentRow ).select();
                                    data = newLog;
                                }
                            }
    
                        }else{
                            console.log('current row', currentRow)
                            table2.row( currentRow ).select();
                            data = newLog;
                        }
    
                        // Proceed with updating the data if the user confirms or there is no previous data
                        //table2.row(currentRow).select();
                        previousSelectedRow = currentRow; // Store the current row as the previously selected row  
                        previousLog = newLog; // Store the current row data the previously selected data
    
                    }, 0);
    
                    var isReload = false;
    
                    // Parse the array of chosen resources
                    var grs = data.phonelogs.resources;
                    var grsTemp = data.phonelogs.resources;
    
                    $('#activeLetter').data("logID", data.phonelogs.id);
                    $('#activeLetter').data("letCR_ID", data.phonelogs.CR_ID);
    ...
    

    In my previous code, my isdifferent function will halt the data load, but the select wasn't working correctly.

                function isDifferentLog(log1, log2) {
                    return JSON.stringify(log1) !== JSON.stringify(log2);
                }
    
                    // Check if there is previous data and the user is trying to select a new row
                    if (previousLog && isDifferentLog(previousLog, newLog)) {
                        var userConfirmed = confirm("You have unsaved changes. Do you want to overwrite the previous response?");
                        if (!userConfirmed) {
                            // Deselect the new row immediately
                            // $(currentRow).removeClass('selected');
                            table2.rows().deselect();
                            console.log("unselect all");
    
                            // Re-select the previous row if it exists
                            if (previousSelectedRow) {
                                // $(previousSelectedRow).addClass('selected');
                                // table2.row(previousSelectedRow).select();
                                console.log("put back previous row");
                            }
                            return; // Exit if the user does not confirm
                        }
                    }
    

    Still working on it and will post a final fix, Thanks @kthorngren for your insight though, I really appreciate it (I know I am getting closer).

  • kthorngrenkthorngren Posts: 21,336Questions: 26Answers: 4,951
    Answer ✓

    he data from the newly selected row is still loaded even before the user has a chance to confirm

    When you say data load are you referring to the data from the clicked row, ie var newLog = table2.row(this).data();, or something else?

    Evidently stopPropagation doesn't work as described either

    The intention of the stopPropagation is to stop propagating the click event from bubbling to the Select extension to keep it from selecting the row. I believe this is happening correctly.

    Also note that I changed if (previousLog && isDifferentLog(previousLog, newLog)) { to if ( true ) { as a place holder for the test case to work. You will need to revert this back if you simply copied my example code to your solution.

    Kevin

  • Stacey1134Stacey1134 Posts: 112Questions: 20Answers: 0

    Got it! When the user first selects a record it populates the data, if they select another record it will confirm before overwriting the data, and the correct record is highlighted, if they don't confirm, it will not load the new data and keep the first one highlighted here's the relevant update:

                var previousLog = null; // To store previous data
                var previousSelectedRow = null; // To store the previously selected row
    
                function isDifferentLog(log1, log2) {
                    return JSON.stringify(log1) !== JSON.stringify(log2);
                }
    
                $('#editTable tbody').on('click', 'tr', function (e) {
                    var newLog = table2.row(this).data();
                    var currentRow = this;
                    e.stopPropagation();             
                    console.log('New log selected:', newLog);
                    console.log('Previous log selected:', previousLog);
    
                    // Check if there is previous data and the user is trying to select a new row
                    if (previousLog && isDifferentLog(previousLog, newLog)) {
                        var userConfirmed = confirm("You have unsaved changes. Do you want to overwrite the previous response?");
                        if (!userConfirmed) {
                            e.stopPropagation();
                            
                            // Re-select the previous row if it exists
                            if (previousSelectedRow) {
                                // $(previousSelectedRow).addClass('selected');
                                console.log("put back previous row");
                                e.stopPropagation();
                                table2.row(previousSelectedRow).select();
                            }
                            return; // Exit if the user does not confirm
                        }else{
                            table2.row(currentRow).select();
                        }
                    }
    
                    // Proceed with updating the data if the user confirms or there is no previous data
                    table2.row(currentRow).select();
    
                    previousLog = newLog; // Update the previous data with the new data
                    previousSelectedRow = currentRow; // Store the current row as the previously selected row
    
  • kthorngrenkthorngren Posts: 21,336Questions: 26Answers: 4,951

    I realized there is another issue with the example. If the user deselects a row the confirmation code still runs. Use row().selected() to determine if the row is selected or not. If not then simply return. Move all the code into the setTimeout function. Going back to letting Datatables select / deselect the clicked row so the stopPropagation is not needed and the clicked row selection in the event handler is not needed.
    https://live.datatables.net/notiwaka/3/edit

    Kevin

  • Stacey1134Stacey1134 Posts: 112Questions: 20Answers: 0

    Interesting, the timeout function won't work for my particular instance, but I can see the logic. Luckily, select 'single' prevents the user from deselecting a row so I am okay there, but noted. Thanks so much for your help! Appreciate it. :)

  • kthorngrenkthorngren Posts: 21,336Questions: 26Answers: 4,951

    In what way does it not work. Possibly the 0 timeout is too quick. You may need to adjust ti to 50 or 100 to allow enough time for Select to select the row.

    Kevin

  • Stacey1134Stacey1134 Posts: 112Questions: 20Answers: 0

    No, has to have been something else, i changed the timeout and it still wouldn't load the data from the next records selected. But the code I posted on June 4th worked perfectly. I tried to use the set time out and the row selected thing, doesn't progress correctly or allow the data to load into the quill editors correctly. Good News is the above code works!

Sign In or Register to comment.