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

使用insertUI插入的嵌套Shiny模块中ObserveEvent未触发的解决方法

解决Shiny动态插入模块中browser()不触发的问题

问题出在调用子模块服务器的方式上:你在mod_server里调用mod_server2(ns("mod_inner")),但moduleServer的第一个参数应该直接传入未经过命名空间包装的模块ID字符串,因为父模块的session已经会自动处理命名空间嵌套了。

修正步骤

  • 将mod_server2(ns("mod_inner"))改为mod_server2("mod_inner")
  • 保留insertUI里的mod_ui2(ns("mod_inner"))(UI部分需要用父模块的ns包装子模块ID,这部分原本是正确的)

修正后的完整代码

library(shiny)

mod_ui <- function(id) {
  ns <- NS(id)
  div(
    id = ns("place_here"),
    actionButton(ns("add"), "Add")
  )
}

mod_server <- function(id) {
  moduleServer(id, function(input, output, session){
    ns <- session$ns
    observeEvent(input$add, {
      insertUI(
        immediate = TRUE,
        selector = paste0("#", ns("place_here")),
        where = "beforeEnd", 
        ui = mod_ui2(ns("mod_inner"))
      )
      # 直接传入字符串ID,无需ns包装
      mod_server2("mod_inner")
    })
  })
}

mod_ui2 <- function(id){
  ns <- NS(id)
  actionButton(ns("test"), "Test")
}

mod_server2 <- function(id) {
  moduleServer(id, function(input, output, session){
    ns <- session$ns
    observeEvent(input$test, {
      browser()
    })
  })
}

ui <- fluidPage(
  mod_ui("mod_top")
)

server <- function(input, output, session){
  mod_server("mod_top")
}

shinyApp(ui = ui, server = server)

原理说明

moduleServer会自动利用父模块的session上下文处理命名空间,若传入ns("mod_inner"),相当于给子模块ID多套了一层命名空间,导致服务器端监听的input$test与UI端按钮ID不匹配,无法触发browser()。直接传字符串ID,moduleServer会结合父模块命名空间生成正确的监听路径,与UI端ID对应后即可正常触发断点。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 20:25:20