DT表重新渲染时下拉列表被禁用[闪亮]

问题描述 投票:0回答:1

我有带有嵌套下拉列表的 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)
    
  })
  
}

r shiny dt
1个回答
0
投票

我一直不太明白为什么,但是重新渲染表格时必须解除绑定。您可以通过回调来做到这一点:

      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)
© www.soinside.com 2019 - 2024. All rights reserved.