Shiny中修改用户筛选后的表格并同步更新主表的实现问题
问题描述
我参考了DT仓库的相关代码实现Shiny表格的用户编辑功能,当前需求如下:
- 基于大型数据库实现编辑前先按material字段筛选,再进行表格编辑,重点支持stockobj列的修改
- 筛选后的编辑表和全量主表需同步展示所有历史修改
预期应用效果如下图:
现有代码
library(DT) library(tidyverse) df<- tibble(material=c(12345,12345,12345,12345,12345, 67891,67891,67891,67891,67891), centro=c("H01", "H02", "H03", "H04","H05","H01", "H02", "H03", "H04","H05" ), rotaSem= c(0.66,0.55,0.43,0.45, 0.33, 0.34,0.78, 0.31,0.89,0.87), stockobj=c(1,2,1,1,3,1,1,1,2,1)) shinyApp( ui = fluidPage( titlePanel("My app"), selectInput("mate", "Select material", choices = unique(df$material)), h3("Edit table"), DTOutput('x1'), h3("Main table"), DTOutput("x2") ), server = function(input, output, session) { x = df categ<-reactive({ x %>% filter(material==input$mate) }) output$x1 <- renderDT(categ(), selection = 'none', rownames = F, editable = T) output$x2 <- renderDT({ x }) proxy = dataTableProxy('x1') observeEvent(input$x1_cell_edit, { info = input$x1_cell_edit str(info) i = info$row j = info$col + 1 # column index offset by 1 v = info$value x[i, j] <<- DT::coerceValue(v, x[i, j]) replaceData(proxy, x, resetPaging = FALSE, rownames = FALSE) }) } )
问题核心
编辑筛选后的表格需要修改reactive返回的对象,直接修改无法实现,求可行思路。
解决方案
核心修改思路如下:
- 用
reactiveVal存储全量主表,保证数据变更可以触发所有依赖组件的自动更新 - 给原始数据增加唯一行标识,避免筛选后行号错位导致修改错误
- 编辑时通过唯一行标识定位全量表中的对应行,修改后更新
reactiveVal存储的主表,两个表格会自动同步变更
修改后可直接运行的完整代码:
library(DT) library(tidyverse) df<- tibble(material=c(12345,12345,12345,12345,12345, 67891,67891,67891,67891,67891), centro=c("H01", "H02", "H03", "H04","H05","H01", "H02", "H03", "H04","H05" ), rotaSem= c(0.66,0.55,0.43,0.45, 0.33, 0.34,0.78, 0.31,0.89,0.87), stockobj=c(1,2,1,1,3,1,1,1,2,1)) %>% mutate(row_id = row_number()) # 新增唯一行标识 shinyApp( ui = fluidPage( titlePanel("My app"), selectInput("mate", "Select material", choices = unique(df$material)), h3("Edit table"), DTOutput('x1'), h3("Main table"), DTOutput("x2") ), server = function(input, output, session) { # 用reactiveVal存储全量主表,支持响应式更新 raw_df = reactiveVal(df) # 筛选后的编辑用子表 categ<-reactive({ raw_df() %>% filter(material==input$mate) %>% select(-row_id) # 隐藏行标识列 }) output$x1 <- renderDT(categ(), selection = 'none', rownames = F, editable = T) # 主表直接渲染全量数据 output$x2 <- renderDT({ raw_df() %>% select(-row_id) }, rownames = F) proxy = dataTableProxy('x1') observeEvent(input$x1_cell_edit, { info = input$x1_cell_edit i = info$row j = info$col + 1 # 列索引偏移 v = info$value # 拿到当前筛选子表对应的全量表行id target_row_id = raw_df() %>% filter(material==input$mate) %>% pull(row_id) %>% .[i] # 更新全量表 new_df = raw_df() new_df[new_df$row_id == target_row_id, j] <- DT::coerceValue(v, new_df[new_df$row_id == target_row_id, j]) raw_df(new_df) # 替换编辑表数据 replaceData(proxy, categ(), resetPaging = FALSE, rownames = FALSE) }) } )
内容的提问来源于stack exchange,提问作者Manuel Vásquez
相关产品推荐
相关产品推荐

