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

单元格编辑后如何保持DT(DataTables)的行展开/折叠状态?

保持DT行组的展开/折叠状态

要解决编辑单元格后行组全部展开的问题,核心思路是在更新数据前记录当前行组的展开状态,数据更新后再恢复这些状态,具体实现如下:

实现步骤

  • 前端通过JS监听行组的点击事件,将每个行组的展开状态同步到Shiny输入对象中
  • 在后端处理单元格编辑、更新数据后,调用自定义JS代码根据记录的状态恢复行组的展开/折叠

修改后的完整代码

library(shiny)
library(DT)

ui <- fluidPage(
  titlePanel("Collapse/Expand table"),
  mainPanel(
    tabsetPanel(
      tabPanel("table1", dataTableOutput("my_table"))
    )
  )
)

server <- function(input, output, session) {
  
  myData <- mtcars[1:15, 1:5]
  
  output$my_table <- DT::renderDataTable({
    datatable(
      myData,
      extensions = 'RowGroup',
      options = list(rowGroup = list(dataSrc = 3), pageLength = 20),
      callback = JS(
        # 初始化时折叠所有行组
        "table.one('init', () => $('#my_table .dtrg-group').trigger('click'));",
        # 监听行组点击,同步状态到Shiny输入
        "table.on('click', 'tr.dtrg-group', function () {",
        "  var groupIndex = $(this).index('.dtrg-group');",
        "  var isExpanded = !$(this).nextUntil('.dtrg-group').hasClass('hidden');",
        "  Shiny.setInputValue('group_states', {index: groupIndex, expanded: isExpanded});",
        "});"
      ),
      selection = 'none',
      editable = 'cell'
    )
  })
  
  # 存储行组的展开状态
  groupStates <- reactiveVal(list())
  
  observeEvent(input$group_states, {
    states <- groupStates()
    states[[as.character(input$group_states$index)]] <- input$group_states$expanded
    groupStates(states)
  })
  
  proxy = dataTableProxy("my_table")
  observeEvent(input$my_table_cell_edit, {
    info = input$my_table_cell_edit
    myData <<- editData(myData, info)
    replaceData(proxy, myData, resetPaging = FALSE, clearSelection = FALSE)
    
    # 恢复行组状态
    isolate({
      states <- groupStates()
      if(length(states) > 0){
        session$sendCustomMessage("restore_group_states", states)
      }
    })
  })
  
  # 接收恢复状态的消息,执行前端操作
  observeEvent(input$restore_group_states, {
    runjs(
      "var states = Shiny.inputBindings.get('shiny.action').getValue('restore_group_states');",
      "$('.dtrg-group').each(function(index) {",
      "  var isExpanded = states[index.toString()];",
      "  var rows = $(this).nextUntil('.dtrg-group');",
      "  if(isExpanded === false && !rows.hasClass('hidden')) {",
      "    rows.addClass('hidden');",
      "  } else if(isExpanded === true && rows.hasClass('hidden')) {",
      "    rows.removeClass('hidden');",
      "  }",
      "});"
    )
  })
}

# Run the application
shinyApp(ui = ui, server = server)

代码说明

  1. 前端状态跟踪:点击行组时,将行组的索引和展开状态通过Shiny.setInputValue传给后端,存储到groupStates响应式变量中
  2. 数据更新后恢复:调用replaceData更新数据后,通过自定义消息将存储的状态传回前端,遍历行组并恢复对应的展开/折叠状态
  3. 初始化折叠:保留了原代码中初始化时折叠所有行组的逻辑

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 10:37:28