Restore state of selected rows
Restore state of selected rows
gwhn
Posts: 4Questions: 0Answers: 0
Hi. I need to restore the selected rows when a user goes back to the DataTable. I have used the bStateSave flag to restore the page length, search filter, current page etc which does not restore the row selection. I've had a look at the functions _fnSaveState and _fnLoadState in the DataTables code, but because the row selection functionality is a feature of TableTools, I was wondering what the best approach would be.
Thank you Allan for such a useable and feature rich component.
Thank you Allan for such a useable and feature rich component.
This discussion has been closed.
Replies
The method using the API to do this would be to use these methods:
http://datatables.net/usage/callbacks#fnStateLoadCallback
http://datatables.net/usage/callbacks#fnStateSaveCallback
And call a state saving event each table the row selection changes.
However, I wonder if it might be slightly easier to just create your own cookie for this exact case, rather than hooking into the DataTables one. You will still need to update your cookie when the row selection changes ( http://datatables.net/extras/tabletools/initialisation#fnRowSelected and fnRowDeselected ), and then reinstate it when the page is reloaded, but I suspect that it will be easier, and you will have more control, for if you do want to store that information on the server (via an Ajax request) to get around the 4KiB limit.
Regards,
Allan
[code]
function storeSelectedRows(node) {
var selected = this.fnGetSelected();
var rowIds = [];
for (var i = 0, j = selected.length; i < j; i++) {
rowIds.push(selected[i].rowIndex);
}
createCookie("DataTables_Row_Selection", rowIds.join(","), 1);
}
[/code]
I found I had to use the fnInitComplete callback, rather than the fnStateLoadCallback, so that calling fnGetNodes worked because the data had already been retrieved from the server. I also discovered that the this reference didn't refer to the DataTable in the fnStateLoadCallback, and that attempting to call fnGetNodes via oSettings.oInstance returned null. Also note that rowIndex is 1 based and fnGetNodes expects a 0 based row index.
[code]
"fnInitComplete": function (oSettings) {
var selection = readCookie("DataTables_Row_Selection").split(",");
for (var i = 0, j = selection.length; i < j; i++) {
var node = this.fnGetNodes(selection[i] - 1);
var select = TableTools.fnGetInstance(oSettings.sTableId).s.select;
$(node).addClass(select.selectedClass);
select.selected.push(node);
}
}
[/code]
I'd be interested in any feedback you have on this approach. Thank you very much for you help. You definitely deserve a few beers on me.
Regards,
Allan
[code]
function storeSelectedRows(oTT) {
var selection = oTT.fnGetSelected();
var rowIds = [];
for (var i = 0, j = selection.length; i < j; i++) {
if (selection[i] !== null) {
rowIds.push(selection[i].rowIndex);
}
}
createCookie("DataTables_" + oTT.s.dt.sTableId + "_Row_Selection", rowIds.join(","), 1);
}
[/code]
And I've added a custom handler for fnClick that stores the row selection too.
[code]
"aButtons": [
{
"sExtends": "select_all",
"fnClick": function (nButton, oConfig) {
this.fnSelectAll();
storeSelectedRows(this);
}
},
{
"sExtends": "select_none",
"fnClick": function (nButton, oConfig) {
this.fnSelectNone();
storeSelectedRows(this);
}
}
],
[/code]
Now I'm going to have to bind to DataTables column sort, pagination and page length events as there aren't any callbacks for this purpose as far as I can tell.
Allan
[code]
"fnRowCallback": function (nRow, aData, iDisplayIndex, iDisplayIndexFull) {
$(nRow).attr("id", this.fnSettings().sTableId + "_" + aData[1]);
return nRow;
},
[/code]
I call a function that stores the row selection from TableTools' fnRowSelected and fnRowDeselected. I also extended the select_all and select_none buttons, using fnSelect to store the row selection, and fnSelect and fnComplete to enable/disable the buttons.
[code]
"oTableTools": {
"sRowSelect": "multi",
"fnRowSelected": function (nNode) {
storeSelectedRows(this);
},
"fnRowDeselected": function (nNode) {
storeSelectedRows(this);
},
"aButtons": [
{
"sExtends": "select_all",
"fnClick": function (nButton, oConfig) {
this.fnSelectAll();
storeSelectedRows(this);
},
"fnSelect": function (nButton, oConfig) {
setSelectAllButtonState(this, nButton);
},
"fnComplete": function (nButton, oConfig) {
setSelectAllButtonState(this, nButton);
}
},
{
"sExtends": "select_none",
"fnClick": function (nButton, oConfig) {
this.fnSelectNone();
storeSelectedRows(this);
},
"fnSelect": function (nButton, oConfig) {
setSelectNoneButtonState(this, nButton);
},
"fnComplete": function (nButton, oConfig) {
setSelectNoneButtonState(this, nButton);
}
}
]
}
[/code]
These are the function definitions used above:
[code]
function storeSelectedRows(oTT) {
var selection = oTT.fnGetSelected();
var rowIds = [];
for (var i = 0, j = selection.length; i < j; i++) {
if (selection[i] !== null) {
rowIds.push(selection[i].id);
}
}
createCookie("DataTables_" + oTT.s.dt.sTableId + "_Row_Selection", rowIds.join(","), 1);
}
function setSelectNoneButtonState(oTT, nButton) {
if (oTT.fnGetSelected().length !== 0) {
$(nButton).removeClass("DTTT_disabled");
} else {
$(nButton).addClass("DTTT_disabled");
}
}
function setSelectAllButtonState(oTT, nButton) {
if (oTT.fnGetSelected().length == oTT.s.dt.fnRecordsDisplay()) {
$(nButton).addClass("DTTT_disabled");
} else {
$(nButton).removeClass("DTTT_disabled");
}
}
[/code]
Finally, to restore the row selection I used the fnDrawCallback to react to changes to page number, length, search filter, sort order etc.
[code]
"fnDrawCallback": function () {
restoreSelectedRows(this);
},
"fnInitComplete": function (oSettings) {
restoreSelectedRows(this);
}
[/code]
These are the function definitions used above:
[code]
function restoreSelectedRows(oDT) {
var settings = oDT.fnSettings();
var cookie = readCookie("DataTables_" + settings.sTableId + "_Row_Selection");
if (cookie === null) return;
var selection = cookie.split(",");
var select = TableTools.fnGetInstance(settings.sTableId).s.select;
var nodes = oDT.fnGetNodes();
for (var m = 0, n = nodes.length; m < n; m++) {
for (var i = 0; i < selection.length; i++) {
if (selection[i] === nodes[m].id) {
$(nodes[m]).addClass(select.selectedClass);
select.selected.push(nodes[m]);
selection.splice(i, 1);
}
}
}
}
[/code]
Concatenating the table's id with the row's id means using more bytes and hitting the 4kb limit sooner, so I expect to have to swap using cookies for storing row selections server-side.
Allan - Thanks for your help and I look forward to the next installment. I hope this proves useful to others while we wait for the feature to be incorporated in to a future version of DataTables.