Fabian Gehring
Fabian Gehring

Reputation: 1173

Dynamically add tab to navbarPage and select new tab

I'm trying to add a new tab to shiny's navbar page whenever another tab is clicked in the navbar.

The following works as expected, but I'd like to jump to the newly added tab (instead of jumping back to "Home").

ui.R

library(shiny)

shinyUI(
  fillPage(
    uiOutput("updateableNavbar")
  )

)

server.R

function(input, output, session) {
  navbarParams <- reactiveValues(
    params = list(
      id = "navbar", 
      title = "navbar", 
      home = tabPanel("Home", titlePanel("Home")),
      add = navbarMenu("AddPanels",
                       tabPanel("AddPanel1", titlePanel("AddPanel1")), 
                       tabPanel("AddPanel2", titlePanel("AddPanel2"))
      )
    )
  )

  lastPanelKlicked <- NULL
  observe({    
    if(!is.null(input$navbar) && substr(input$navbar, 1, 8) == "AddPanel" && 
         (is.null(lastPanelKlicked) || lastPanelKlicked != input$navbar)) {   
      lastPanelKlicked <<- input$navbar
      print(input$navbar)
      params <- navbarParams$params
      params[[length(params) + 1]] <- tabPanel(input$navbar, titlePanel(input$navbar))
      names(params)[length(params)] <- input$navbar
      navbarParams$params <<- params
    }
  })  

  output$updateableNavbar <- renderUI({
    do.call(navbarPage, navbarParams$params)
  })  
}

Upvotes: 0

Views: 672

Answers (1)

K. Rohde
K. Rohde

Reputation: 9676

How about that?

### server.R

function(input, output, session) {

  navbarParams <- reactiveValues(
    params = list(
      id = "navbar", 
      title = "navbar", 
      home = tabPanel("Home", titlePanel("Home")),
      add = navbarMenu("AddPanels",
                       tabPanel("AddPanel1", titlePanel("AddPanel1")), 
                       tabPanel("AddPanel2", titlePanel("AddPanel2"))
      )
    )
  )

  lastPanelKlicked <- NULL
  makeReactiveBinding("lastPanelKlicked")

  observe({    
    if(!is.null(input$navbar) && substr(input$navbar, 1, 8) == "AddPanel" && 
       (is.null(lastPanelKlicked) || paste0("Add", lastPanelKlicked) != input$navbar)) {

      # Above and below I changed the Value of lastPanelClicked

      lastPanelKlicked <<- substr(input$navbar, 4, 1000)
      print(lastPanelKlicked)
      params <- navbarParams$params
      params[[length(params) + 1]] <- tabPanel(lastPanelKlicked, titlePanel(lastPanelKlicked))
      names(params)[length(params)] <- lastPanelKlicked
      navbarParams$params <<- params
    }
  })  

  output$updateableNavbar <- renderUI({
    do.call(navbarPage, navbarParams$params)
  })  

  observe({
    updateNavbarPage(session, "navbar", lastPanelKlicked)
  })

}

I basically made lastPanelKlicked reactive such that after your parameters are set, the observe-statement with updateNavbarPage is triggered.

One problem though, is that you assigned tabPanel-IDs multiple times. All your panels (in your original code) are either called AddPanel1 or AddPanel2 and if you want to select a panel, it selects the first one with this name (which is the one in the navbarMenu). So I had to rename your generated panels with either Panel1 or Panel2 to illustrate how it works.

If you want to apply this solution, I recommend you to think of a pattern how to name your tabs such that you can call them unambiguously.

Please ask, if something is unclear!

Upvotes: 1

Related Questions