Home > Mobile >  How to create dynamic tabSetPanels with the same selected tab that reacts to user input in R Shiny?
How to create dynamic tabSetPanels with the same selected tab that reacts to user input in R Shiny?

Time:09-27

My app contains two tabSetPanel that are created based on user input (in the example below the user input is a group of radio buttons). The user input determines both the number of tabs in both tabSetPanels AND the selected tab. I also want the two tabSetPanels to display the same tab whenever user input is changed or different tab is selected in either sets. The original app contains feature that prevents me from merging the two tabSetPanels. The problem is that both tabSetPanels initially display tabs without any content. Here is a minimal reproducible example:

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)
}

Thanks in advance

CodePudding user response:

  • The value of a tabPanel must be a character string :

    output$set1 <- renderUI({
      tabs <- list()
      for(i in seq_len(input$tabSelector)){
        tabs[[i]] <- tabPanel(
          title = paste0("tab",i),
          value = as.character(i),
          numericInput(
            paste0("num",i),
            "Number",
            value = 0
          )
        )
      }
      do.call(tabsetPanel, c(tabs,
                             list(id = "set1",
                                  selected = as.character(input$tabSelector))
      ))
    })
    
  • In output$set2 you don't need to set the value of the selected argument, because it will be set by the updateTabsetPanel.

  • Duplicated ids are not allowed in HTML, so you have to change the id paste0("num",i) of your numeric inputs to something else in one of the two tabsets.

  • Related