Reputation: 11
I would like to embed numericInput and checkBoxInput in a data table. I have an example from Xie Yihui that works perfectly fine. Exactly like what I wanted. But when the code is wrapped in a module, the edited table does not update. I read that this could be due to namespace but I do not know how to fix it.
Here are the Gists:
Gist: edit DataTable in Shiny App
Gist: edit DataTable in Shiny Module
Upvotes: 0
Views: 488
Reputation: 6155
There was just one little fix, which is of course hard to see if you're not familiar with Shiny modules. Every Input ID you create in the Module Server function has to be wrapped in ns
(as you do in the UI), but this function is hidden in session$ns
in the server function. So in line 18, where the inputs are created, their ID had to be adjusted using session$ns
. From
inputs[i] = as.character(FUN(paste0(id, i), label = NULL, ...))
to
inputs[i] = as.character(FUN(paste0(session$ns(id), i), label = NULL, ...))
Full code:
library(shiny)
library(DT)
editTableUI <- function(id) {
ns <- NS(id)
tagList(
DT::dataTableOutput(ns('x1')),
verbatimTextOutput(ns('x2'))
)
}
editTable <- function(input, output, session) {
# create a character vector of shiny inputs
shinyInput = function(FUN, len, id, ...) {
inputs = character(len)
for (i in seq_len(len)) {
inputs[i] = as.character(FUN(paste0(session$ns(id), i), label = NULL, ...))
}
inputs
}
# obtain the values of inputs
shinyValue = function(id, len) {
unlist(lapply(seq_len(len), function(i) {
value = input[[paste0(id, i)]]
if (is.null(value)) NA else value
}))
}
# a sample data frame
res = data.frame(
v1 = shinyInput(numericInput, 100, 'v1_', value = 0),
v2 = shinyInput(checkboxInput, 100, 'v2_', value = TRUE),
v3 = rnorm(100),
v4 = sample(LETTERS, 100, TRUE),
stringsAsFactors = FALSE
)
# render the table containing shiny inputs
output$x1 = DT::renderDataTable(
res, server = FALSE, escape = FALSE, options = list(
preDrawCallback = JS('function() {
Shiny.unbindAll(this.api().table().node()); }'),
drawCallback = JS('function() {
Shiny.bindAll(this.api().table().node()); } ')
)
)
# print the values of inputs
output$x2 = renderPrint({
data.frame(v1 = shinyValue('v1_', 100), v2 = shinyValue('v2_', 100))
})
}
shinyApp(
ui = fluidPage(
editTableUI("test")
),
server = function(input, output) {
callModule(editTable, "test")
}
)
Upvotes: 1