save DataTable state or row selections

718 views
Skip to first unread message

Ron Hylton

unread,
Nov 25, 2014, 6:30:39 PM11/25/14
to shiny-...@googlegroups.com
Hello.

I'm trying to write an application in which the user can select an arbitrary set of rows in a DataTable by clicking on a row or a checkbox in the row to toggle the row selection state.  The table is long and pageable.

In my initial attempts I stored the visual selection indicator in the DataTable and sent it to R using Shiny.onInputChange.  This didn't work because of the server-side DataTable processing; as the user paged the table R knew what was selected but the visual selection indicators got lost since Shiny didn't know about them.

My second attempt stores the selection indicator in a column in the table and re-renders the table whenever there's a change in the selection state.  Unfortunately this doesn't work either, because while the state indicator does get displayed properly there is other user state in the DataTable (page number, number of rows per page, filter values, search value) which gets lost when the table is re-rendered.

DataTables has a stateSave option which looked like it might fix this but unfortunately setting it didn't help.  I suspect this has something to do with how the Shiny server-side processing works.

There are also stateSaveCallback and stateLoadCallback options, but my attempts to use the first just hang up the browser and I'm not even sure what I would do with the second.

I might be able to work around the problem by making the table non-pageable and moving the filter boxes to the top (I haven't tried this but presumably it's possible) but it's not ideal.

Does anyone have a solution to the big problem, which is keeping row-selection synchronized between R and the visual selection indicator in a pageable DataTable without disturbing the DataTable?

Or a way to save/restore the DataTable state?

Or maybe just a better way to do row selection?

Thanks,
Ron

Ron Hylton

unread,
Nov 28, 2014, 12:27:14 PM11/28/14
to shiny-...@googlegroups.com
I figured out a solution.   The row selection information can be saved in the browser in sessionStorage, and then the DataTable createdRow callback can be used to set the indicator on rows as they are recreated during paging.

Ron

Herman Sontrop

unread,
Nov 30, 2014, 9:38:16 AM11/30/14
to shiny-...@googlegroups.com
Would you mind sharing the code you use which does this part?

Vincent

unread,
Nov 30, 2014, 5:06:14 PM11/30/14
to shiny-...@googlegroups.com
Is sessionStorage also accessible from R? This is not shiny's session object or is it?

Ron Hylton

unread,
Nov 30, 2014, 6:12:09 PM11/30/14
to shiny-...@googlegroups.com
This is the "usual" callback code that toggles the selected state and tells R the new state.

 
 function(table) {
  table
.on('click.dt', 'tr', function() {
 
var sel = $(this).toggleClass('selected').hasClass('selected');
 
var rowId = [0 1 2].map(function(i){return this.eq(i).text();},$(this).children('td'));
 
Shiny.onInputChange('inputId',JSON.stringify([rowId,sel]));
 
var list = sessionStorage.tableId_selected;
 
if(list==null) {list=[];} else {list=JSON.parse(list);}
  rowId
=JSON.stringify(rowId);
 
if(sel){list.push(rowId);} else {while((i=list.indexOf(rowId))>=0){list.splice(i, 1);}}
  sessionStorage
.tableId_selected=JSON.stringify(list);
 
});



This is the createdRow callback.

function(row,data,dataIndex) {
 
var rowId = [0 1 2].map(function(i){return this[i].innerHTML;},row.querySelectorAll('td'));
 
var list=sessionStorage.tableId_selected;
 
if(list!=null) {
  list
=JSON.parse(list);
 
if(list.indexOf(JSON.stringify(rowId))>=0){
  $
(row).addClass('selected');
 
}}}


Replace [0 1 2] with whatever set of columns constitutes a unique row identifier for your table.  This would be neater if Shiny supprted DT_RowID https://groups.google.com/forum/?utm_medium=email&utm_source=footer#!topic/shiny-discuss/_1h6eStpr2U.
Replace tableId_selected with something that identifies your table in sessionStorage.

The createdRow callback will need to be wrapped in I().




Herman Sontrop

unread,
Dec 1, 2014, 6:31:36 PM12/1/14
to shiny-...@googlegroups.com
Thanks for sharing!
Reply all
Reply to author
Forward
0 new messages