Shiny 1.8.0中如何绑定DT数据表内的下拉选择输入?
问题解决:Shiny 1.8.0下DT表格内嵌selectInput无法绑定的问题
问题背景
升级到Shiny 1.8.0后,原有的DT表格内嵌selectInput的实现失效,点击动作按钮时无法获取下拉框的选中值(返回NULL),原因是Shiny的输入绑定机制发生了变更,旧的绑定逻辑不再适配。
解决方案
核心是调整Shiny输入绑定的时机,配合DT的preDrawCallback和drawCallback来正确处理动态生成的输入控件:
- 提前解绑旧绑定:在表格重新绘制前解绑所有旧的输入绑定,避免冲突
- 延后绑定新控件:在表格绘制完成后,仅对包含输入控件的单元格重新绑定
- 修正容器结构:移除不必要的行级容器类,利用selectInput自带的容器结构完成绑定
修正后的完整代码
library(shiny) library(DT) tabledata <- data.frame(name = c('Cat', 'Dog', 'Mouse'), code = c('C','D','M'), status = NA) ui <- fluidPage( titlePanel("demo"), sidebarLayout( sidebarPanel('blank'), mainPanel( DT::dataTableOutput('mytab'), actionButton(inputId = 'check', label = 'Check') ) ) ) server <- function(input, output) { # 生成每行的selectInput下拉框 for (i in 1:nrow(tabledata)) { tabledata$status[i] <- as.character(selectInput( inputId = tabledata$code[i], label = "", choices = c("X", "Y", "Z"), selected = "Y" )) } output$mytab = DT::renderDataTable( tabledata, escape = FALSE, selection = 'none', server = FALSE, rownames = FALSE, options = list( dom = 't', paging = FALSE, ordering = FALSE, # 绘制前解绑所有旧绑定 preDrawCallback = JS("function() { Shiny.unbindAll(this.api().table().node()); }"), # 绘制完成后仅绑定含输入控件的单元格 drawCallback = JS("function() { this.api().cells(':has(.shiny-input-container)').every(function() { Shiny.bindAll(this.node()); }); }") ) ) observeEvent(input$check,{ print(input$C) # 现在可正常获取Cat对应的下拉选择值 }) } shinyApp(ui = ui, server = server)
关键修改说明
- 移除了原
callback中行级shiny-input-container类的添加操作,selectInput本身已自带该容器结构 - 用
preDrawCallback在表格重绘前完成旧绑定解绑,避免内存泄漏和绑定冲突 - 在
drawCallback中精准定位包含输入控件的单元格进行绑定,提升执行效率 - 简化了inputId的生成逻辑,直接使用
tabledata$code[i]即可满足需求
内容的提问来源于stack exchange,提问作者Simon Gillings
相关产品推荐
相关产品推荐

