bslib::page_navbar dynamically show/hide panels

,

Hi, is there any way to dynamically show/hide panels in bslib::navbar? I've tried few thgins but none worked or I get warning:

Warning: Navigation containers expect a collection of `bslib::nav_panel()`/`shiny::tabPanel()`s and/or `bslib::nav_menu()`/`shiny::navbarMenu()`s. Consider using `header` or `footer` if you wish to place content above (or below) every panel's contents.

which basicly puts all panels into one. My approach was to put all required panels into div and then hide that div using shinyjs::hide. Below is small example. Is it possible to dynamicly hide second panel if there are 0 observations?

# ------------------------
# Module 1: generate data
# ------------------------
my_mod1_ui <- function(id) {
  ns <- NS(id)
  tagList(
    sliderInput(ns("n"), "Number of observations", min = 0, max = 100, value = 100)
  )
}

my_mod1_server <- function(id) {
  moduleServer(id, function(input, output, session) {
    # reactive dataset
    reactive({
      rnorm(input$n)
    })
  })
}

# ------------------------
# Module 2: show histogram
# ------------------------
my_mod2_ui <- function(id) {
  ns <- NS(id)
  tagList(
    plotOutput(ns("hist"))
  )
}

my_mod2_server <- function(id, data_reactive = NULL) {
  moduleServer(id, function(input, output, session) {
    output$hist <- renderPlot({
      req(data_reactive())   # ensure data is available
      hist(data_reactive(), main = "Histogram", col = "skyblue", border = "white")
    })
  })
}

# ------------------------
# Main UI
# ------------------------
ui <- tagList(
  bslib::page_navbar(
    title = "myApp",
    bslib::nav_panel(
      title = "1st Panel",
      my_mod1_ui("mod1")
    ),
    bslib::nav_panel(
      title = "2nd Panel",
      my_mod2_ui("mod2")
    )
  )
)

# ------------------------
# Main server
# ------------------------
server <- function(input, output, session) {
  df <- my_mod1_server("mod1")      # returns reactive data
  my_mod2_server("mod2", df)        # pass reactive data to module 2
}

# ------------------------
# Run app
# ------------------------
shinyApp(ui, server)

It sounds like you want bslib::nav_insert() and bslib::nav_remove(). See this example from the docs:

library(shiny)
library(bslib)

ui <- page_fluid(
  actionButton("add", "Add 'Dynamic' tab"),
  actionButton("remove", "Remove 'Foo' tab"),
  navset_tab(
    id = "tabs",
    nav_panel("Hello", "hello"),
    nav_panel("Foo", "foo"),
    nav_panel("Bar", "bar tab")
  )
)
server <- function(input, output) {
  observeEvent(input$add, {
    nav_insert(
      "tabs", target = "Bar", select = TRUE,
      nav_panel("Dynamic", "Dynamically added content")
    )
  })
  observeEvent(input$remove, {
    nav_remove("tabs", target = "Foo")
  })
}
shinyApp(ui, server)

Thanks for answer. It seems to me that this way I would need to destroy/create modules each time, but your answer lead me to following implementation:

specifying id="panel" inpage_navbar and:

server <- function(input, output, session) {
  
  df <- my_mod1_server("mod1")      # returns reactive data
  
  observe({
    bslib::nav_hide("panel", "2nd Panel", session)
    req(df())
    bslib::nav_show("panel", "2nd Panel", session = session)
  })
  
  my_mod2_server("mod2", df)        # pass reactive data to module 2
}

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.

If you have a query related to it or one of the replies, start a new topic and refer back with a link.