Dear community,
I have a shiny app in which I am creating some controls dynamically (tabs, checkboxes and plots).
I am looking for some advice on How to remove the dynamically created controls.
I have tried using removeUI, which indeed removes the controls on the user interface. However when looking at what happens server-side the dynamically created controls are still present (I am using the shiny.reactlog).
What strategy should I use to remove these unused controls and avoid potential memory leaks?
I have included a sample application below. Some parts could have been written using shiny_modules but I did not want to add an extra layer of complexity.
To reproduce these observations:
- start rstudio
options(shiny.reactlog=TRUE)
- start the app (code below)
- Click on Add controls (controls are created)
- Click on Remove controls (controls are removed)
- Open the react log (press Ctrl + F3)
- Replay the script using Right-arrow key
You will notice that despite using removeUI no nodes are removed from the graph.
Than you in advance for your help.
library(shiny)
library(shinydashboard)
library(ggplot2)
# Define UI for miles per gallon app ----
ui <- pageWithSidebar(
# App title ----
headerPanel("Adding/Removing controls dynamically"),
# Sidebar panel for inputs ----
sidebarPanel(
sliderInput(inputId = "n_controls", value = 2, min = 0, max = 5, label = "controls to add"),
actionButton("addcontrols", "Add controls"),
actionButton("removecontrols", "Remove Controls")
),
# Main panel for displaying outputs ----
mainPanel(
uiOutput("all_controls")
)
)
# Define server logic to plot various variables against mpg ----
server <- function(input, output) {
observeEvent(input$addcontrols, {
output$all_controls <- renderUI({create_tabset(
isolate(input$n_controls), input, output)
})
})
observeEvent(input$removecontrols, {
#remove tabset
removeUI(".tabbable", immediate = TRUE)
})
}
ns_prefix<- function(type, id) {
paste("dynamic", type, id, sep = "_")
}
create_tabset <- function(number_controls, input, output) {
force(number_controls)
# create a list of tabs
myTabs <- lapply(1:number_controls, create_tab, input = input, output = output)
myTabs <- unname(myTabs)
# create a tabset containing the tabs
out <- do.call(tabsetPanel, c(myTabs, list(id = "alltabs")))
out
}
create_tab <- function(number, input, output) {
# create controls
controls <- create_controls(number)
# create tabpanel with embedded controls
tab <- tabPanel(title = sprintf("Title%s", number),
value = number,
controls)
# Make the checkbox in the tab reactive
input_check <- reactive({input[[ns_prefix("check", number)]]})
# Bind the checkbox event and the plot
output[[ns_prefix("plot", number)]] <- renderPlot({create_plot(is_red = input_check())})
tab
}
create_controls <- function(number) {
# create list of controls
# using ns_prefix to assign a specific prefix
out <- tagList(
div(
checkboxInput(inputId = ns_prefix("check", number), label = sprintf("Checkbox%s", number)),
plotOutput(outputId = ns_prefix("plot", number))
)
)
}
create_plot <- function(df = iris, is_red) {
# choose color
col <- if (is_red) "red" else "black"
# make plot
out <- ggplot(iris, aes(Sepal.Length, Sepal.Width)) +
geom_point(color = col)
out
}
shinyApp(ui, server)