Created
March 9, 2024 16:54
-
-
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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