如何使用R Shiny moduleServer实现多输出及模块间数据传递
问题修正方案
现有代码核心问题
- 模块内存储编辑后数据的
x是普通变量,不是响应式对象,修改后无法触发父服务端的渲染更新 - 主UI中错误使用服务端渲染函数
renderDT,应该使用UI输出组件DTOutput - 模块返回值调用方式错误,无需额外加
$x后缀 - 模块UI中存在无用的
NS(id,"x")代码
修正后可运行完整代码
library(shiny) library(tidyverse) library(plotly) library(DT) library(shinydashboard) # 基础数据---- default_df <- structure(list(`0` = 70, `1` = 70, `2` = 70, `3` = 70, `4` = 70, `5` = 70, `6` = 70, `7` = 70, `8` = 70, `9` = 70, `10` = 70, `11` = 70, `12` = 70, `13` = 70, `14` = 70, `15` = 70, `16` = 70, `17` = 70, `18` = 70, `19` = 70, `20` = 70, `21` = 70, `22` = 70, `23` = 70), row.names = "calls", class = "data.frame") # 模块---- ## 模块服务端---- mod_editable_srv <- function(id, data) { moduleServer(id, function(input, output, session) { # 使用reactiveVal存储响应式可变数据 x = reactiveVal(data) proxy = dataTableProxy('x1') observeEvent(input$x1_cell_edit, { info = input$x1_cell_edit i = info$row j = info$col v = info$value # 更新响应式数据 current_x <- x() current_x[i, j] <- DT::coerceValue(v, current_x[i, j]) x(current_x) replaceData(proxy, current_x, resetPaging = FALSE) }) output$x1 = renderDT(x(), selection = 'none', editable = TRUE) # 返回响应式对象供父服务端调用 return(x) }) } ## 模块UI---- mod_editable_ui <- function(id) { tagList( DT::dataTableOutput(NS(id, "x1")) ) } # 主UI---- header <- dashboardHeader(title = "可编辑模块测试") table <- column(width = 8, box(width = 12, title = "可编辑输入表格", mod_editable_ui('x1') ), box(width = 12, title = "模块输出同步结果", DT::DTOutput('test_dat') ) ) body <- dashboardBody(table) ui <- dashboardPage( header, dashboardSidebar(disable = TRUE), body ) # 主服务端---- server <- function(input, output) { datafile <- mod_editable_srv("x1", default_df) output$test_dat <- renderDT({ datafile() }) } # 运行应用---- shinyApp(ui = ui, server = server)
关键逻辑说明
moduleServer模式下模块向父服务端传值的核心规则是:所有需要同步的动态数据必须封装为响应式对象(reactiveVal/reactive),模块直接返回该响应式对象,父服务端调用时加()即可获取最新值。
后续如果要新增plotly交互输入功能,只需要在模块内监听plotly的交互事件,同步更新同一个reactiveVal即可,父端无需额外修改就能同时获取两种输入方式修改后的最新数据。
内容的提问来源于stack exchange,提问作者rwhit
相关产品推荐
相关产品推荐

