如何在Shiny中动态生成argonTabItem并实现标签页正常切换
问题背景
我正在开发基于argonDash的Shiny应用,预期效果如下(静态实现代码):
library(argonDash) library(argonR) library(shiny) ui <- argonDashPage( header = argonDashHeader( color = "header_custom", gradient = TRUE, top_padding = 3, bottom_padding = 3 ), sidebar = argonDashSidebar( id = "app_sidebar", vertical = TRUE, side = "left", size = "md", background = "sidebar_custom", wellPanel(id = "well_panel", argonDash::argonSidebarMenu( shiny::br(), argonDash::argonSidebarItem(tabName = "home", "Home", icon = htmltools::tags$i(class = paste0("fa fa-home"))), shiny::br(), argonDash::argonSidebarItem(tabName = "study_metrics", "Study Metrics",icon = argonR::argonIcon(name = "sound-wave")), shiny::br(), argonDash::argonSidebarItem(tabName = "demo_app", "Demo App"), shiny::br() ) ) ), body = argonDashBody( id = "app_body", argonTabItems( argonTabItem(tabName = "home", p("Test")), argonTabItem(tabName = "study_metrics", br(),textInput('id_study_metrics', 'text', placeholder = 'study_metrics') ), argonTabItem(tabName = "demo_app", br(),textInput('id_demo_app', 'text', placeholder = 'demo_app') ) ) ), footer = NULL ) server <- function(input, output, session) { } shinyApp(ui, server)
(对应效果:
)
需求与问题
我需要动态生成以下部分的argonTabItem(因后续该列表会扩展):
argonTabItem(tabName = "study_metrics", br(),textInput('id_study_metrics', 'text', placeholder = 'study_metrics') ), argonTabItem(tabName = "demo_app", br(),textInput('id_demo_app', 'text', placeholder = 'demo_app') )
我尝试通过以下代码实现动态生成:
library(argonDash) library(argonR) library(shiny) ui <- argonDashPage( header = argonDashHeader( color = "header_custom", gradient = TRUE, top_padding = 3, bottom_padding = 3 ), sidebar = argonDashSidebar( id = "app_sidebar", vertical = TRUE, side = "left", size = "md", background = "sidebar_custom", wellPanel(id = "well_panel", argonDash::argonSidebarMenu( shiny::br(), argonDash::argonSidebarItem(tabName = "home", "Home", icon = htmltools::tags$i(class = paste0("fa fa-home"))), shiny::br(), argonDash::argonSidebarItem(tabName = "study_metrics", "Study Metrics",icon = argonR::argonIcon(name = "sound-wave")), shiny::br(), argonDash::argonSidebarItem(tabName = "demo_app", "Demo App"), shiny::br() ) ) ), body = argonDashBody( id = "app_body", argonTabItems( argonTabItem(tabName = "home", p("Test")), uiOutput("apps_ui") ) ), footer = NULL ) server <- function(input, output, session) { apps_fns <- c("id_study_metrics", "id_demo_app") prefix_removed <- sub("id_", "", apps_fns) output$apps_ui <- renderUI({ lapply(seq_along(apps_fns), function(i) { argonTabItem( tabName = prefix_removed[i], br(), textInput(apps_fns[i], "text", placeholder = prefix_removed[i]) ) }) }) } shinyApp(ui, server)
但实现后,所有输入控件都集中显示在同一页面,无法实现标签页的正常切换(效果:
)。我尝试过使用tagList等方法,均未解决问题,恳请提供有效的解决方案。
解决方案
问题核心是argonTabItems要求直接将argonTabItem作为子元素,而你把动态生成的标签页放在了uiOutput容器中,导致这些argonTabItem不是argonTabItems的直接子节点,标签切换逻辑无法识别它们。
正确的做法是将整个argonTabItems的内容都动态生成,包括固定的Home标签页,确保所有argonTabItem都是argonTabItems的直接子元素。修改后的代码如下:
library(argonDash) library(argonR) library(shiny) ui <- argonDashPage( header = argonDashHeader( color = "header_custom", gradient = TRUE, top_padding = 3, bottom_padding = 3 ), sidebar = argonDashSidebar( id = "app_sidebar", vertical = TRUE, side = "left", size = "md", background = "sidebar_custom", wellPanel(id = "well_panel", argonDash::argonSidebarMenu( shiny::br(), argonDash::argonSidebarItem(tabName = "home", "Home", icon = htmltools::tags$i(class = paste0("fa fa-home"))), shiny::br(), argonDash::argonSidebarItem(tabName = "study_metrics", "Study Metrics",icon = argonR::argonIcon(name = "sound-wave")), shiny::br(), argonDash::argonSidebarItem(tabName = "demo_app", "Demo App"), shiny::br() ) ) ), body = argonDashBody( id = "app_body", # 用uiOutput动态生成整个argonTabItems内容 uiOutput("all_tab_items") ), footer = NULL ) server <- function(input, output, session) { apps_fns <- c("id_study_metrics", "id_demo_app") prefix_removed <- sub("id_", "", apps_fns) output$all_tab_items <- renderUI({ # 先创建固定的Home标签页 tab_items <- list( argonTabItem(tabName = "home", p("Test")) ) # 动态添加其他标签页 dynamic_tabs <- lapply(seq_along(apps_fns), function(i) { argonTabItem( tabName = prefix_removed[i], br(), textInput(apps_fns[i], "text", placeholder = prefix_removed[i]) ) }) # 合并所有标签页,传入argonTabItems do.call(argonTabItems, c(tab_items, dynamic_tabs)) }) } shinyApp(ui, server)
如果希望保留Home标签页在UI中静态定义,也可以通过do.call让动态生成的标签页直接成为argonTabItems的子元素,但全动态生成的方案扩展性更强,更适合后续列表扩展的需求。
内容的提问来源于stack exchange,提问作者user16024709
相关产品推荐
相关产品推荐

