R Shiny中DT表格复选框点击更新按钮后无法同步更新求助
解决Shiny DT复选框状态重置问题
问题根源在于表格更新时,DT的JS回调没有根据新数据的select1值同步重置复选框状态,而是保留了DOM中旧的选中状态。以下是修正后的完整代码,重点调整了preDrawCallback和drawCallback的逻辑:
library(shiny) library(DT) ui <- fluidPage( sidebarLayout( sidebarPanel( selectInput("species", "选择物种", choices = unique(iris$Species)), actionButton("update", "更新表格") ), mainPanel( fluidRow( column(6, DTOutput("left_table")), column(6, DTOutput("right_table")) ) ) ) ) server <- function(input, output, session) { # 原始数据 raw_data <- reactiveVal(iris) # 左侧表格数据(带复选框) left_data <- reactive({ req(input$update) isolate({ df <- subset(raw_data(), Species == input$species) df$select1 <- FALSE df }) }) # 右侧表格数据(同步选中状态) right_data <- reactive({ req(left_data()) df <- left_data() # 获取左侧表格的复选框选中状态 selected_rows <- input$left_table_rows_selected if (!is.null(selected_rows)) { df$select1[selected_rows] <- TRUE } else { df$select1 <- FALSE } df }) output$left_table <- renderDT({ req(left_data()) datatable( left_data(), selection = "multiple", options = list( preDrawCallback = JS('function(settings) { // 移除之前绑定的事件,避免重复触发 $(settings.nTable).off("click", "input[type=checkbox]"); }'), drawCallback = JS('function(settings) { var api = this.api(); var rows = api.rows({page: "current"}).nodes(); // 遍历行,根据select1值设置复选框状态 rows.each(function(index) { var rowData = api.row(index).data(); var checkbox = $(this).find("input[type=checkbox]"); checkbox.prop("checked", rowData.select1); }); // 绑定复选框点击事件,同步选中行到Shiny输入 $(settings.nTable).on("click", "input[type=checkbox]", function() { var $row = $(this).closest("tr"); var rowIdx = api.row($row).index(); var isChecked = $(this).prop("checked"); // 更新Shiny的选中行输入 var selected = api.rows({selected: true}).indexes().toArray(); if (isChecked) { if (!selected.includes(rowIdx)) { selected.push(rowIdx); } } else { selected = selected.filter(function(idx) { return idx !== rowIdx; }); } Shiny.setInputValue("left_table_rows_selected", selected); }); }') ), # 生成复选框列 callback = JS('table.column(0).nodes().to$().css({width: "50px"});') ) %>% formatStyle("select1", target = "row", backgroundColor = styleEqual(c(TRUE, FALSE), c("#ccebc5", "#ffffff"))) }) output$right_table <- renderDT({ req(right_data()) datatable( right_data(), options = list(dom = "t"), selection = "none" ) %>% formatStyle("select1", target = "row", backgroundColor = styleEqual(c(TRUE, FALSE), c("#ccebc5", "#ffffff"))) }) } shinyApp(ui, server)
关键修正点:
- preDrawCallback:在每次绘制表格前移除旧的复选框点击事件绑定,避免重复触发逻辑导致状态混乱。
- drawCallback:表格绘制完成后,遍历所有行,根据当前行
select1列的布尔值强制设置复选框的checked状态,确保新数据加载时状态完全同步。 - 选中状态同步:点击复选框时,手动管理
left_table_rows_selected的Shiny输入值,确保与复选框状态一致,进而同步到右侧表格。
这样修改后,当你切换物种并点击更新按钮时,右侧表格的复选框状态会随新数据的select1值(初始为FALSE)重置,不再保留之前的选中状态。
内容的提问来源于stack exchange,提问作者TobKel
相关产品推荐
相关产品推荐

