Reputation: 348
I have a problem inside a bigger app, I narrowed it to this repex
I have a DT table inside a module. I need to get data from rows of that table by clicking on it. For that, I use the callback param from DT::renderDataTable
Outside the module, it's fine. Inside the module, I can't get the click event data back. In the explorer console, it says that the value doesn't exist, so it can't log it.
library(shiny)
library(DT)
tableUI <- function(id){
ns <- NS(id)
tagList(
DT::dataTableOutput(ns("mytable"))
textOutput(ns("mytext"))
)
}
tableServer <- function(id){
moduleServer(id, function(input, output, session){
output$mytable = DT::renderDataTable({
mtcars
},
callback = JS('table.on("click.dt", "tr",
function() {
data = table.rows(this).data().toArray();
Shiny.setInputValue("mytext1", data, {priority: "event"});
console.log(mytext1);
});')
)
observeEvent(req(input$mytext1), {
output$mytext <- renderText(input$mytext1)
})
})
}
ui <- basicPage(
tableUI("table1")
)
server <- function(input, output) {
tableServer("table1")
}
shinyApp(ui, server)
I tried adding the ns id to the setInputValue id, like "mytable-mytext1", but that gives me a shiny error and the app doesn't even start:
Warning: Error in eval: object 'mytext1' not found
[No stack trace available]
Upvotes: 3
Views: 2142
Reputation: 11908
You need to include the module namespace with Shiny.setInputValue()
. You
mention trying with "mytable-mytext1"
but that’s using the table ID, not
the module ID to build the namespace. Instead, you’d want "table1-mytext1"
.
A better way to build that would be with sessions$ns()
(see below).
Furthermore, for the example you showed, you don’t need to use a custom
callback
in the first place. You can instead make use of the built in
input that DT creates for the last clicked row.
library(shiny)
library(DT)
tableUI <- function(id) {
ns <- NS(id)
tagList(
DT::dataTableOutput(ns("mytable")),
textOutput(ns("mytext1")),
textOutput(ns("mytext2")),
)
}
tableServer <- function(id) {
moduleServer(id, function(input, output, session) {
output$mytable <- DT::renderDataTable(
mtcars,
callback = JS(sprintf(
'table.on("click.dt", "tr", function() {
data = table.rows(this).data().toArray();
Shiny.setInputValue("%s", data);
});', session$ns("mytext1")))
)
output$mytext1 <- renderText(req(input$mytext1))
output$mytext2 <- renderText({
row <- mtcars[req(input$mytable_row_last_clicked), ]
# Need to append rowname to match the JavaScript result
c(rownames(row), as.character(row))
})
})
}
ui <- basicPage(
tableUI("table1")
)
server <- function(input, output) {
tableServer("table1")
}
shinyApp(ui, server)
Upvotes: 5