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

如何在Shiny子模块中点击动态按钮显示隐藏的Tab2?

问题解决方法

你的代码存在两个核心问题:

  1. 动态按钮的JS代码硬编码了Input ID,未适配模块命名空间,导致模块内的监听事件无法正确触发
  2. 模块内直接调用showTab时使用的是模块子Session,无法操作主UI中的navbar_page元素

以下是修改后的完整代码:

library(data.table)
library(dplyr)
library(shiny)
library(DT)

# 修改按钮生成函数,接受命名空间ID参数
make_button <- function(ns_id){
  function(i){
    sprintf(
      '<button id="btn_tab2_%d" type="button" class="btn btn-light"
       onclick="%s"><span class="glyphicon glyphicon-search"></span> </button>', 
      i, sprintf("Shiny.setInputValue('%s', this.id);", ns_id))
  }
}

# Catalog server module
catalog_server <- function(input, output, session) {
  ns <- session$ns
  
  # 创建项目列表,使用模块命名空间生成按钮的Input ID
  df_list_projects <- shiny::reactiveVal({
    df <- iris
    cbind(df,
          button = sapply(1:nrow(df), make_button(ns("button"))),
          stringsAsFactors = FALSE)
  })
  
  # 渲染数据表
  output[["tbl1"]] = DT::renderDT(
    DT::datatable(df_list_projects(), escape = F)
  )
  
  # 创建响应式信号,用于向主Server传递按钮点击事件
  button_clicked <- reactive({
    input$button
  })
  
  # 显示弹窗
  observeEvent(input$button, {
    showModal(modalDialog(
      title = "Showing tab2",
      size = "s",
      easyClose = TRUE,
      footer = NULL
    ))
  })
  
  # 返回响应式信号给主Server
  return(button_clicked)
}

# Catalog UI module
catalog_ui <- function(id) {
  ns <- NS(id)
  div(style = "height: 100%",
      class = "jumbotron",
      id = ns("project_panel"),
      shinyWidgets::useSweetAlert(),
      fluidRow(
        column(12,
               column(12, DT::DTOutput(outputId = ns("tbl1")))
        )
      ))
}

# Shiny app UI
ui <- shiny::tagList(
  navbarPage(id = "navbar_page",
             title = "test",
             
             collapsible = TRUE,
             tabPanel("Tab1",
                      catalog_ui(id = "tab1_page")),
             
             tabPanel("Tab2",
                      catalog_ui(id = "tab2_page"))
  ))

# Shiny app server
server <- function(input, output, session) {
  
  # 调用模块并接收按钮点击信号
  tab1_button_signal <- shiny::moduleServer(id = "tab1_page",
                      module = catalog_server, session)
  
  # 初始隐藏Tab2
  shiny::hideTab(inputId = "navbar_page",
                 target = "Tab2",
                 session = session)
  
  # 监听模块传来的信号,显示Tab2
  observeEvent(tab1_button_signal(), {
    shiny::showTab(inputId = "navbar_page",
                   target = "Tab2",
                   session = session)
  })
  
}

# Run the app
shinyApp(ui, server)

关键修改点说明

  • 适配模块命名空间:修改make_button函数,让它接收模块的命名空间ID,生成符合Shiny模块规范的Input ID,确保模块内的input$button能正确监听到点击事件
  • 分离UI操作逻辑:模块只负责处理弹窗显示和传递点击信号,将showTab操作移到主Server中执行,因为主Server拥有操作主UI元素的权限
  • 响应式信号传递:模块返回一个响应式值,主Server监听该值来触发Tab显示操作,符合Shiny模块的解耦设计原则

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 20:03:14