简体   繁体   中英

How do I toggle a cell class in a shiny DT datatable?

Using Shiny and DT, I want to trigger an event for specific cells in a datatable. Suppose I want the first column to turn red on hover. When I create the table I add a callback that registers a hover event on the td elements in the first column.

library(shiny)
library(DT)

ui <- fluidPage(
  tags$head(tags$style(HTML(".red { background-color: red; }"))),
  DT::dataTableOutput("iris")
)

server <- function(input, output) {
  output$iris <- DT::renderDataTable(DT::datatable(iris, callback = JS("
table.column(0).nodes().to$().hover(function(){$(this).toggleClass('red');});
")))
}

shinyApp(ui = ui, server = server)

From the javascript console if I run the identical code it works :

table=$('#DataTables_Table_0').DataTable()
table.column(0).nodes().to$().hover(function(){$(this).toggleClass('red');});

Why doesn't this work in the datatable callback? What is the right way to do this?

Usually when you see this sort of behaviour, it suggests a timing issue. The callback is being called back before the table is fully rendered, the the columns you want to operate on don't exist just quite yet.

Remove the callback option and use options = list( drawCallback = JS(...) ) instead.

DT::datatable(
  iris,
  options = list(
    drawCallback = JS('function() {this.api().table().column(0).nodes().to$().hover(function(){$(this).toggleClass("red")}) }')
  )
)

For completeness, here are three solutions: drawCallback , rowCallback , and table.on . drawCallback was given as the answer, above. columnDefs can be used to assign a class to a column, which makes it easy to use selectors. rowCallback is an alternative to drawCallback. And, last, events can be assigned using on() in the datatables API for mouse events, but you must manage both mouseenter and mouseleave instead of jQuery's hover() convenience method. (I find this last solution perplexing because the documentation (1) does not have a second selector parameter and (2) mouse events are not listed in the events API , but that's what works!)

Important, only one of these is needed, not all three! Personally, I like the rowCallback as the most concise.

library(shiny)
library(DT)

ui <- fluidPage(
  tags$head(tags$style(HTML(".red { background-color: red; }"))),
  div(id='tbl1', DT::dataTableOutput("iris"))
)

server <- function(input, output) {
  output$iris <- DT::renderDataTable(DT::datatable(iris, 
                                                   options = list(drawCallback=JS("function() { this.api().table().column(0).nodes().to$().hover(function(){$(this).toggleClass('red');}); }"),
                                                                  rowCallback=JS("function(row) { $(row).children('.firstcol').hover(function(){$(this).toggleClass('red')}) }"),
                                                                  columnDefs=list(list(className='firstcol', targets=0))),
                                                    callback = JS("
 table.on('mouseenter', 'td.firstcol', function() { $(this).addClass('red'); });
 table.on('mouseleave', 'td.firstcol', function() { $(this).removeClass('red'); });
")))
}

shinyApp(ui = ui, server = server)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM