如何在R Shiny中创建选中标签同步且响应用户输入的动态tabSetPanels
问题现象
我的应用包含两个基于用户输入创建的tabSetPanel(下方示例中用户输入为一组单选按钮)。用户输入会同时决定两组tabSetPanels的标签数量以及默认选中的标签。我还希望每当用户输入变更,或是在任意一组标签页中选中不同标签时,两个tabSetPanels都能展示相同的标签。原始应用的功能限制导致我无法合并这两个tabSetPanels,目前的问题是两个tabSetPanels初始加载时展示的标签都没有任何内容。
最小可复现示例
library(shiny) ui <- fluidPage( sidebarLayout( sidebarPanel( # User input for number of tabs and selected tab radioButtons("tabSelector", "Select Number of Tabs", 1:3, 1), br() ), mainPanel( uiOutput( "set1" ), uiOutput( "set2" ) ) ) ) server <- function(input, output, sesstion){ output$set1 <- renderUI({ tabs <- list() for(i in seq_len(input$tabSelector)){ tabs[[i]] <- tabPanel( title = paste0("tab",i), value = i, numericInput( paste0("num",i), "Number", value = 0 ) ) } do.call(tabsetPanel, c(tabs, list(id = "set1", selected = input$tabSelector))) }) output$set2 <- renderUI({ tabs <- list() for(i in seq_len(input$tabSelector)){ tabs[[i]] <- tabPanel( title = paste0("tab",i), value = i, numericInput( paste0("num",i), "Number", value = 0 ) ) } do.call(tabsetPanel, c(tabs, list(id = "set2", selected = input$tabSelector))) }) # Bind the two tabSetPanels observeEvent(input$set1, { updateTabsetPanel(inputId = "set2", selected = input$set1) }) observeEvent(input$set2,{ updateTabsetPanel(inputId = "set1", selected = input$set2) }) } # end server function if (interactive()) { shinyApp(ui, server) }
问题原因
- 核心错误是
server函数的第三个参数拼写错误,把session写成了sesstion,导致updateTabsetPanel无法获取会话对象执行更新操作 observeEvent默认开启ignoreInit = TRUE,初始加载时不会触发同步逻辑- 两个标签组内的输入控件使用了相同ID,存在DOM ID冲突问题,可能导致控件渲染异常
修复方案
library(shiny) ui <- fluidPage( sidebarLayout( sidebarPanel( radioButtons("tabSelector", "选择标签数量", 1:3, 1), br() ), mainPanel( uiOutput("set1"), hr(), uiOutput("set2") ) ) ) server <- function(input, output, session){ # 抽离公共的标签生成逻辑,减少重复代码 generate_tabs <- function(prefix = "set1") { tabs <- list() for(i in seq_len(input$tabSelector)){ tabs[[i]] <- tabPanel( title = paste0("tab",i), value = i, numericInput( paste0(prefix, "_num",i), "数值", value = 0 ) ) } return(tabs) } output$set1 <- renderUI({ do.call(tabsetPanel, c(generate_tabs("set1"), list(id = "set1", selected = input$tabSelector))) }) output$set2 <- renderUI({ do.call(tabsetPanel, c(generate_tabs("set2"), list(id = "set2", selected = input$tabSelector))) }) # 关闭ignoreInit,初始加载就执行同步 observeEvent(input$set1, { updateTabsetPanel(session = session, inputId = "set2", selected = input$set1) }, ignoreInit = FALSE) observeEvent(input$set2,{ updateTabsetPanel(session = session, inputId = "set1", selected = input$set2) }, ignoreInit = FALSE) } if (interactive()) { shinyApp(ui, server) }
内容的提问来源于stack exchange,提问作者Abdallah Atef
相关产品推荐
相关产品推荐

