问题
I wanted to add the functionality of something happening after a table cell was clicked (e.g. open a modal). Because (suppose my dt is has the ID "dt") input$dt_cell_clicked
stays the same until I click a new cell, I cannot execute the same event on re-clicking that cell.
I tried working around it resetting input$dt_cell_clicked
with javascript manually. This works, but there seems to be an internal updatemarker in DT that noticed I clicked the cell before and does not set the value of input$dt_cell_clicked
to the clicked value. Is there a workaround or is this a bug?
Thanks!
Minimal example:
library(shiny)
library(shinyjs)
ui <- fluidPage(
h2("Last clicked:"),
verbatimTextOutput("last_clicked"),
actionButton("reset", "Reset clicked value"),
h2("Datatable:"),
DT::dataTableOutput("dt"),
useShinyjs(),
extendShinyjs(text = paste0("shinyjs.resetDTClick = function() { Shiny.onInputChange('dt_cell_clicked', null); }"))
)
server <- function(input, output) {
# the last clicke value
output$last_clicked <- renderPrint({
str(input$dt_cell_clicked)
})
output$dt <- DT::renderDataTable({
DT::datatable(head(mtcars, 2))
})
observeEvent(input$dt_cell_clicked, {
validate(need(length(input$dt_cell_clicked) > 0, ''))
alert("You clicked something!")
})
observeEvent(input$reset, {
js$resetDTClick()
})
}
shinyApp(ui, server)
回答1:
After the hint of using a proxy (Gregor de Cillia), I found a workaround using a detour: the last selected cell. This last selected cell is observed and some action is executed upon a new selection. We can reset the selection by using a DT proxy.
library(shiny)
ui <- fluidPage(
h2("Last clicked:"),
verbatimTextOutput("last_clicked"),
actionButton("reset", "Reset clicked value"),
h2("Datatable:"),
DT::dataTableOutput("dt")
)
server <- function(input, output) {
# the last clicked=selected value
output$last_clicked <- renderPrint({
str(input$dt_rows_selected)
})
output$dt <- DT::renderDataTable({
DT::datatable(head(mtcars, 2), selection = 'single')
})
# do some action after selecting a value
observeEvent(input$dt_rows_selected, {
validate(need(!is.null(input$dt_rows_selected), ''))
print("You clicked something!")
})
myProxy = DT::dataTableProxy('dt')
# reset last selected value using the proxy
observeEvent(input$reset, {
DT::selectRows(myProxy, NULL)
})
}
shinyApp(ui, server)
回答2:
Here is a version that does resets correctly. It uses a reactive value (called last
) that gets set to NULL
whenever the reset button is pressed and takes the value of input$dt_cell_clicked
whenever this value is updated.
I also removed the dependency from shinyjs
by using a dataTableProxy
together with selectRows
library(shiny)
ui <- fluidPage(
h2("Last clicked:"),
verbatimTextOutput("last_clicked"),
actionButton("reset", "Reset clicked value"),
h2("Datatable:"),
DT::dataTableOutput("dt")
)
server <- function(input, output) {
# the last clicke value
output$last_clicked <- renderPrint({
str(last())
})
output$dt <- DT::renderDataTable({
DT::datatable(head(mtcars, 2))
})
observeEvent(input$dt_cell_clicked, {
validate(need(length(input$dt_cell_clicked) > 0, ''))
print("You clicked something!")
})
myProxy = DT::dataTableProxy('dt')
last = reactiveVal(NULL)
observe({
last(input$dt_cell_clicked)
})
observeEvent(input$reset, {
DT::selectRows(myProxy, NULL)
last(NULL)
output$dt <- DT::renderDataTable({ # EDIT
DT::datatable(head(mtcars, 2)) # EDIT
}) # EDIT
})
}
shinyApp(ui, server)
来源:https://stackoverflow.com/questions/45065715/datatables-dt-reset-value-of-clicked-cell