You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Shiny DT表格selectInput响应式数据更新后失效问题修复

Shiny DT表格重载后输入控件响应失效的最小改动解决方案

之前遇到Shiny DT表格重载后输入控件响应性问题,当时采用JavaScript解绑的方案在静态数据场景下有效,但在响应式数据场景中失效。

具体问题表现:首次点击「Update data」加载数据时,selectInput可正常工作,input$id1能响应用户选择;但再次点击更新响应式数据后,input$id1不再响应。

已知两种解决思路:使用dataTableProxy()与replaceData(),或每次更新时重命名selectInput的ID,现寻求无需这两种方案的最小改动解决办法。

错误代码示例

require(shiny)
require(DT)

shinyApp(
  ui = fluidPage(
    tags$head(tags$script(
      HTML(
        "Shiny.addCustomMessageHandler('unbindDT', function(id) {
            var $table = $('#'+id).find('table');
            if($table.length > 0){
              Shiny.unbindAll($table.DataTable().table().node());
            }
          })")
    )),
    actionButton(inputId = "update", label = "Update data"),
    uiOutput("resettable_table")
  ),
  server = function(input, output, session) {
    rv <- reactiveValues(
      times = 1, 
      mydata = NULL
    )
    
    observeEvent(input$update, {
      session$sendCustomMessage("unbindDT", "mytable")
      rv$times <- rv$times + 1
      rv$mydata <- data.frame(
        Col1 = as.character(selectInput(
          inputId = "id1",
          label = NULL,
          choices = paste0(letters, input$update),
          selected = paste0(letters, input$update)[1],
        ))
      )
    })
    
    output$mytable <- DT::renderDataTable({
      req(rv$mydata)
      DT::datatable(
        data = rv$mydata,
        escape = F,
        selection = "none",
        options = list(
          preDrawCallback = JS('function(){Shiny.unbindAll(this.api().table().node());}'),
          drawCallback = JS('function(){Shiny.bindAll(this.api().table().node());}')
        )
      )
    }, server = F)
    
    output$resettable_table <- renderUI({
      req(rv$times)
      div(
        id = paste0("mydiv", rv$times),
        DT::dataTableOutput("mytable")
      )
    })
    
    observe({
      if(is.null(input$id1)) {
        print("input$id1 is NULL")
      } else {
        print(paste(c("input$id1:", input$id1)))
      }
    })
    
  })

修复说明及代码

感谢@StephaneLaurent指出问题根源:用于记录数据重载次数的响应式计数器,以及将DT表格置于ID动态更新的div中这一操作导致了失效。修复时只需移除动态div和计数器,直接渲染DT表格即可。

修复后的代码如下:

require(shiny)
require(DT)

shinyApp(
  ui = fluidPage(
    tags$head(tags$script(
      HTML(
        "Shiny.addCustomMessageHandler('unbindDT', function(id) {
            var $table = $('#'+id).find('table');
            if($table.length > 0){
              Shiny.unbindAll($table.DataTable().table().node());
            }
          })")
    )),
    actionButton(inputId = "update", label = "Update data"),
    DT::dataTableOutput("mytable")
  ),
  server = function(input, output, session) {
    rv <- reactiveValues(mydata = NULL)
    
    observeEvent(input$update, {
      session$sendCustomMessage("unbindDT", "mytable")
      rv$mydata <- data.frame(
        Col1 = as.character(selectInput(
          inputId = "id1",
          label = NULL,
          choices = paste0(letters, input$update),
          selected = paste0(letters, input$update)[1],
        ))
      )
    })
    
    output$mytable <- DT::renderDataTable({
      req(rv$mydata)
      DT::datatable(
        data = rv$mydata,
        escape = F,
        selection = "none",
        options = list(
          preDrawCallback = JS('function(){Shiny.unbindAll(this.api().table().node());}'),
          drawCallback = JS('function(){Shiny.bindAll(this.api().table().node());}')
        )
      )
    }, server = F)
    
    observe({
      if(is.null(input$id1)) {
        print("input$id1 is NULL")
      } else {
        print(paste(c("input$id1:", input$id1)))
      }
    })
    
  })

内容的提问来源于stack exchange,提问作者Ben Ernest

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 05:50:29