Skip to content

Instantly share code, notes, and snippets.

@hypebright
Created March 9, 2024 16:54
Show Gist options
  • Save hypebright/7ad632c7e6b3a9e32779757831fc2b59 to your computer and use it in GitHub Desktop.
Save hypebright/7ad632c7e6b3a9e32779757831fc2b59 to your computer and use it in GitHub Desktop.
Demo demonstrating how to dynamically add and remove Shiny modules, and how to properly clean up modules once removed by using the destroy() method.
# Dynamic UI: demonstrate destroy() method on observer
# This example makes use of a module that dynamically creates pages
# Each server part of the module creates an observer that listens to an actionButton
# Whenever a page is removed, the observer is destroyed. The UI is removed with
# the nav_remove() function.
library(shiny)
library(bslib)
sportsPageUI <- function(id, page_name) {
ns <- NS(id)
tagList(
h2(page_name),
card(
card_header("General Info"),
card_body(
textOutput(ns("general_info")),
actionButton(ns("notification"), "Show notification")
)
)
)
}
sportsPageServer <- function(id, chosen_sport, r) {
moduleServer(id, function(input, output, session) {
output$general_info <- renderText({
sprintf("%s is the sports you have chosen!", chosen_sport)
})
my_observer <-
observe({
showNotification(sprintf("Welcome to the %s page!", chosen_sport))
}) |> bindEvent(input$notification)
r$observer_list[[id]] <- my_observer
})
}
ui <- page_navbar(
id = "navbar_id",
title = "Destroy modules",
nav_menu(title = "Sports",
icon = icon("basketball-ball"),
nav_panel(title = "Add sports",
icon = icon("cogs"),
selectInput("sports_to_add",
label = "Choose sports to add",
choices = c("Baseball",
"Basketball",
"Football",
"Tennis"),
selected = NULL,
multiple = TRUE)
)
)
)
server <- function(input, output, session) {
r <- reactiveValues(active_pages = NULL,
observer_list = list())
observe({
chosen_sports <- input$sports_to_add
lapply(chosen_sports, function(this_sport) {
if (this_sport %in% r$active_pages) {
# the sport already has a page, and is chosen by the user, so don't do anything
return()
}
nav_insert(id = "navbar_id",
target = "Add sports",
nav = nav_panel(
title = this_sport,
icon = icon("plus-circle"),
sportsPageUI(id = this_sport, page_name = this_sport)
),
position = "after")
sportsPageServer(id = this_sport, chosen_sport = this_sport, r = r)
})
if (setdiff(r$active_pages, chosen_sports) |> length() > 0) {
remove_sports <- setdiff(r$active_pages, chosen_sports)
for (sport in remove_sports) {
nav_remove(id = "navbar_id",
target = sport)
# destroy any existing observers
r$observer_list[[sport]]$destroy()
}
}
r$active_pages <- chosen_sports
}) |> bindEvent(input$sports_to_add)
}
shinyApp(ui, server)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment