我有带有嵌套下拉列表的 dt 表。列表工作正常,直到表被重新渲染(例如,我需要向 DT 表添加额外的记录)。
列表可以工作,但它们的值没有更新(
print(input$<list name>
在重新渲染表格之前生成值)。
我已经使用了here的答案部分中的示例。
我希望下拉列表的值在 input$ 中更新,就像列表“sel1”正在更新
input$sel1
中的 vlue 一样。值更新后,output$sel
也应更新。
我发现的选项是在每次渲染表格时使用具有不同 id 的下拉列表重新渲染表格。但它看起来效率不高而且笨拙。
我使用操作按钮扩展了示例中的脚本以重新呈现表格。 该应用程序如下:
library(shiny)
library(DT)
# this selectInput will not be included in the app;
# we just use it to extract the required HTML dependencies
select_input <- selectInput("x", label = NULL, choices = c("A", "B"))
deps <- htmltools::findDependencies(select_input)
# now you just have to include tagList(deps) somewhere in the Shiny UI
ui <- fluidPage(
actionButton('my_btn', 'Re-render DT table'),
title = 'Selectinput column in a table',
DTOutput('foo'),
verbatimTextOutput('sel'),
tagList(deps)
)
server <- function(input, output, session) {
data <- head(iris, 5)
for (i in 1:nrow(data)) {
data$species_selector[i] <-
as.character(
selectInput(
paste0("sel", i), "",
choices = unique(iris$Species),
width = "100px"
)
)
}
output$foo = renderDT({
datatable(
data, escape = FALSE, selection = 'none',
options = list(
dom = 't',
paging = FALSE,
ordering = FALSE,
initComplete = JS(c(
"function(settings, json) {",
" var $table = this.api().table().node().to$();",
" $table.find('[id^=sel]').selectize();", # apply selectize() to all elements whose id starts with 'sel' (here sel1, sel2, ...)
"}"
)),
preDrawCallback =
JS("function() {Shiny.unbindAll(this.api().table().node());}"),
drawCallback
= JS("function() {Shiny.bindAll(this.api().table().node());}")
)
)
})
output$sel = renderPrint({
str(sapply(1:nrow(data), function(i) input[[paste0("sel", i)]]))
})
observeEvent(input$my_btn,{
output$foo = renderDT({
datatable(
data, escape = FALSE, selection = 'none',
options = list(
dom = 't',
paging = FALSE,
ordering = FALSE,
initComplete = JS(c(
"function(settings, json) {",
" var $table = this.api().table().node().to$();",
" $table.find('[id^=sel]').selectize();", # apply selectize() to all elements whose id starts with 'sel' (here sel1, sel2, ...)
"}"
)),
preDrawCallback =
JS("function() {Shiny.unbindAll(this.api().table().node());}"),
drawCallback
= JS("function() {Shiny.bindAll(this.api().table().node());}")
)
)
})
print(input)
print(input$sel1)
})
}
我一直不太明白为什么,但是重新渲染表格时必须解除绑定。您可以通过回调来做到这一点:
callback = JS(c(
"$('#my_btn').on('click', function() {",
" Shiny.unbindAll(table.table().node());",
"});"
)),
顺便说一句,不要将输出槽放在观察者内部(除非确实没有其他方法)。在这里,您只需将
input$my_btn
插入到 renderDT
中即可。
另一方面,您应该避免重新渲染表格。如果您必须在实际应用程序中添加新记录,请使用代理和 DT 函数
replaceData
。
完整代码:
library(shiny)
library(DT)
# this selectInput will not be included in the app;
# we just use it to extract the required HTML dependencies
select_input <- selectInput("x", label = NULL, choices = c("A", "B"))
deps <- htmltools::findDependencies(select_input)
# now you just have to include tagList(deps) somewhere in the Shiny UI
ui <- fluidPage(
actionButton('my_btn', 'Re-render DT table'),
title = 'Selectinput column in a table',
DTOutput('foo'),
verbatimTextOutput('sel'),
tagList(deps)
)
server <- function(input, output, session) {
data <- head(iris, 5)
for (i in 1:nrow(data)) {
data$species_selector[i] <-
as.character(
selectInput(
paste0("sel", i), "",
choices = unique(iris$Species),
width = "100px"
)
)
}
output$foo = renderDT({
input$my_btn # table will be refreshed on clicking this button
datatable(
data, escape = FALSE, selection = 'none',
callback = JS(c(
"$('#my_btn').on('click', function() {",
" Shiny.unbindAll(table.table().node());",
"});"
)),
options = list(
dom = 't',
paging = FALSE,
ordering = FALSE,
initComplete = JS(c(
"function(settings, json) {",
" var $table = this.api().table().node().to$();",
" $table.find('[id^=sel]').selectize();", # apply selectize() to all elements whose id starts with 'sel' (here sel1, sel2, ...)
"}"
)),
preDrawCallback =
JS("function() {Shiny.unbindAll(this.api().table().node());}"),
drawCallback
= JS("function() {Shiny.bindAll(this.api().table().node());}")
)
)
})
output$sel = renderPrint({
str(sapply(1:nrow(data), function(i) input[[paste0("sel", i)]]))
})
observe({
print(input$sel1)
})
}
shinyApp(ui, server)