使用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
相关产品推荐
相关产品推荐

