R DT datatable not retaining row index/counter column after selecting new page when using callback option
Asked Answered
G

1

4

I am using this question as a reference to add a "row index" or "counter column" (as described in the datatable documentation here) to a DT::datatable in a Shiny application. The intent is to hold the row names in the table constant (1, 2, 3...) regardless of the sorting that is applied to the table.

The user NicE answered this question by converting the javascript code in the datatable documentation for use in the callback of the DT::datatable options:

output$tbl = renderDataTable({
                        datatable(data, filter = "top", rownames=TRUE,options = list(
                            pageLength = 300, lengthMenu = c(100,200,300,400,500,600)
                    ),
                    callback=JS("table.on( 'order.dt search.dt', function () {
                            table.column(0, {search:'applied', order:'applied'}).nodes().each( function (cell, i) {
                                  cell.innerHTML = i+1;});}).draw();"))
            })

This works fine if I run only the datatable(... portion of the code locally; however, it does not work when I run within renderDataTable in the Shiny application (the row names revert to the original sorting when you move to a page other than the first). Per a comment in the datatable documentation linked above, the user DeFKnoL identified that this does not work properly if you move between pages in the table - this is the exact problem when I run my Shiny application. DeFKnoL's comment states that ("deferRender": true) causes issues with this - I have tried changing this to FALSE in the DT::datatable options and this does not fix the problem.

I am hoping someone can help me convert this user's javascript code into something that I can feed into the callback option of DT::datatable.

Here is the javascript code from the original method outlined in the datatable documentation (that NicE modified for use in the callback):

$(document).ready(function() {
var t = $('#example').DataTable( {
    "columnDefs": [ {
        "searchable": false,
        "orderable": false,
        "targets": 0
    } ],
    "order": [[ 1, 'asc' ]]
} );

t.on( 'order.dt search.dt', function () {
    t.column(0, {search:'applied', order:'applied'}).nodes().each( function (cell, i) {
        cell.innerHTML = i+1;
    } );
} ).draw();

} );

And here is DeFKnoL's updated method that gets around the issue of changing pages:

$(document).ready(function() {
var t = $('#example').DataTable( {
    "columnDefs": [ {
        "searchable": false,
        "orderable": false,
        "targets": 0
    } ],
    "order": [[ 1, 'asc' ]]
} );

t.on( 'draw.dt', function () {
var PageInfo = $('#example').DataTable().page.info();
     t.column(0, { page: 'current' }).nodes().each( function (cell, i) {
        cell.innerHTML = i + 1 + PageInfo.start;
    } );
} );

} );

As you can maybe see, NicE's JS() input doesn't exactly match the documentation - and I have no experience with javascript - so I'm having a tough time implementing this change. It is possible that adding a "counter column" is much simpler than this, but I've had no luck finding any methods other than the original question linked above. Any help would be appreciated!

Gupta answered 12/3, 2019 at 6:13 Comment(0)
R
5

Two possibilities:

1) use server = FALSE:

output$tbl <- renderDT({
  datatable(data, filter = "top", rownames=TRUE, 
            options = list(
              pageLength = 300, lengthMenu = c(100,200,300,400,500,600)
            ),
            callback=JS("table.on( 'order.dt search.dt', function () {
              table.column(0, {search:'applied', order:'applied'}).nodes().each( function (cell, i) {
              cell.innerHTML = i+1;});}).draw();")
  )
}, server = FALSE)

2) Otherwise, here is DeFKnoL's method:

js <- c(
  "table.on('draw.dt', function(){",
  "  var PageInfo = table.page.info();",
  "  table.column(0, {page: 'current'}).nodes().each(function(cell,i){", 
  "    cell.innerHTML = i + 1 + PageInfo.start;",
  "  });",
  "})")

output$tbl <- renderDT({
  datatable(data, filter = "top", rownames=TRUE, 
            options = list(
              pageLength = 300, lengthMenu = c(100,200,300,400,500,600)
            ),
            callback = JS(js)
  )
})
Roncesvalles answered 12/3, 2019 at 15:54 Comment(3)
The second method worked perfectly. I was not able to use the first option as the table I am working with could be over 10,000 rows depending on the data that is selected (it worked on a smaller data set - ~500 rows - but not on a larger data set). Thank you!Gupta
Okay, so after putting this into production, it appears the JavaScript is overriding some of the CSS styles I have for the datatables... the column names now revert to right aligned after sorting the table. I have the text-align set to center - which is how it displays when you load the table initially - but the column names change to right-aligned after you sort a column. Do you know why this might be?Gupta
@Luke_ew I don't know sorry. If you open a new question I'll can take a look.Nina

© 2022 - 2024 — McMap. All rights reserved.