Row selection and deselection problem
Row selection and deselection problem
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
You have the wrong syntax. Use the
select.style
option to set single select, like this:In line 70 and 81 of your first snippet you are using something like this:
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: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 userow().select()
orrows().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
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.
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
tosingle
.Is this more along the lines of what you are wanting?
Kevin
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.
In my previous code, my isdifferent function will halt the data load, but the select wasn't working correctly.
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).
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?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)) {
toif ( 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
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:
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
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.
In what way does it not work. Possibly the
0
timeout is too quick. You may need to adjust ti to50
or100
to allow enough time for Select to select the row.Kevin
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!