Title: | Create Destroyable Modules in 'Shiny' |
---|---|
Description: | Enables the complete removal of various 'Shiny' components, such as inputs, outputs and modules. It also aids in the removal of observers that have been created in dynamically created modules. |
Authors: | Ashley Baldry [aut, cre] |
Maintainer: | Ashley Baldry <[email protected]> |
License: | MIT + file LICENSE |
Version: | 0.1.0 |
Built: | 2024-11-15 05:53:18 UTC |
Source: | https://github.com/ashbaldry/shiny.destroy |
This package enables the complete removal of various 'Shiny' components, such as inputs, outputs and modules. It also aids in the removal of observers that have been created in dynamically created modules.
Maintainer: Ashley Baldry [email protected]
For a given 'moduleServer' call, add the code required for {shiny.destroy} to work. This will involve creating the observer list to the user session, and adds all observers within the list.
addDestroyers(module)
addDestroyers(module)
module |
The function call to 'moduleServer' |
An updated version of 'module', where the {shiny.destroy} code has been added.
Given the namespace of a shiny module, remove all references to the inputs, outputs and observers that are called within the module.
destroyModule(id = NULL, session = getDefaultReactiveDomain())
destroyModule(id = NULL, session = getDefaultReactiveDomain())
id |
The module namespace ID. Use 'NULL' to destroy the module the call is being executed in. |
session |
The shiny session, by default it is 'shiny::getDefaultReactiveDomain()' |
No return value, called to remove the relevant module UI and server-side observers.
library(shiny) basicModuleUI <- function(id) { ns <- NS(id) actionButton(ns("click"), "Click Button") } basicModuleServer <- function(id) { moduleServer(id, function(input, output, session) { rv <- reactiveVal(0L) observeEvent(input$click, rv(rv() + 1L)) rv }) } destroyableModuleUI <- makeModuleUIDestroyable(basicModuleUI) destroyableModuleServer <- makeModuleServerDestroyable(basicModuleServer) ui <- fluidPage( destroyableModuleUI(id = "test"), actionButton("destroy", "Destroy module"), textOutput("reactive_value") ) server <- function(input, output, session) { top_rv <- reactiveVal() reactive_value <- destroyableModuleServer("test") observeEvent(reactive_value(), top_rv(reactive_value())) output$reactive_value <- renderText(top_rv()) observeEvent(input$destroy, destroyModule("test")) } shinyApp(ui, server)
library(shiny) basicModuleUI <- function(id) { ns <- NS(id) actionButton(ns("click"), "Click Button") } basicModuleServer <- function(id) { moduleServer(id, function(input, output, session) { rv <- reactiveVal(0L) observeEvent(input$click, rv(rv() + 1L)) rv }) } destroyableModuleUI <- makeModuleUIDestroyable(basicModuleUI) destroyableModuleServer <- makeModuleServerDestroyable(basicModuleServer) ui <- fluidPage( destroyableModuleUI(id = "test"), actionButton("destroy", "Destroy module"), textOutput("reactive_value") ) server <- function(input, output, session) { top_rv <- reactiveVal() reactive_value <- destroyableModuleServer("test") observeEvent(reactive_value(), top_rv(reactive_value())) output$reactive_value <- renderText(top_rv()) observeEvent(input$destroy, destroyModule("test")) } shinyApp(ui, server)
A short description...
isSpecifiedFunction(fn_call, fns)
isSpecifiedFunction(fn_call, fns)
fn_call |
A function call |
fns |
A character vector of functions to compare the function call against |
A logical value stating whether or not the function call is in the collection.
Adding wrappers to a shiny module to enable an ease of dynamically adding and removing modules within a shiny application.
makeModuleUIDestroyable(module_fn, wrapper = shiny::div) makeModuleServerDestroyable(module_fn)
makeModuleUIDestroyable(module_fn, wrapper = shiny::div) makeModuleServerDestroyable(module_fn)
module_fn |
The server-side part of the module |
wrapper |
If the module is a 'shiny::tagList()', then an HTML tag will be wrapped by an HTML tag so that a shiny.destroy attribute can be attached |
An updated function call of 'module_fn'.
For the UI, if the returned object from 'module_fn' is a 'shiny.tag' then an additional attribute will be added to the top-level HTML tag for {shiny.destroy} to reference when removing the UI. If the returned object is a 'shiny.tag.list' then a wrapper tag will surround the module with the attribute to destroy the module.
For the server, each observer will be assigned to the '.shiny.destroy' list within 'session$userData'. The returned object from the module remains the same as before.
library(shiny) # UI basicModuleUI <- function(id) { ns <- NS(id) actionButton("click", "Increase") } destroyableModuleUI <- makeModuleUIDestroyable(basicModuleUI) # Server-side basicMoudleServer <- function(id) { moduleServer(id, function(input, output, session) { rv <- reactiveVal() observeEvent(input$click, rv(input$click)) }) } destroyableModuleServer <- makeModuleServerDestroyable(basicMoudleServer) # Shiny Application ui <- fluidPage( destroyableModuleUI(id = "test"), actionButton("destroy", "Destroy module"), textOutput("reactive_value") ) server <- function(input, output, session) { top_rv <- reactiveVal() reactive_value <- destroyableModuleServer("test") observeEvent(reactive_value(), top_rv(reactive_value())) output$reactive_value <- renderText(top_rv()) observeEvent(input$destroy, destroyModule("test")) }
library(shiny) # UI basicModuleUI <- function(id) { ns <- NS(id) actionButton("click", "Increase") } destroyableModuleUI <- makeModuleUIDestroyable(basicModuleUI) # Server-side basicMoudleServer <- function(id) { moduleServer(id, function(input, output, session) { rv <- reactiveVal() observeEvent(input$click, rv(input$click)) }) } destroyableModuleServer <- makeModuleServerDestroyable(basicMoudleServer) # Shiny Application ui <- fluidPage( destroyableModuleUI(id = "test"), actionButton("destroy", "Destroy module"), textOutput("reactive_value") ) server <- function(input, output, session) { top_rv <- reactiveVal() reactive_value <- destroyableModuleServer("test") observeEvent(reactive_value(), top_rv(reactive_value())) output$reactive_value <- renderText(top_rv()) observeEvent(input$destroy, destroyModule("test")) }
The removal of the named input in a shiny session.
removeInput( id, selector = paste0("#", id), session = getDefaultReactiveDomain() )
removeInput( id, selector = paste0("#", id), session = getDefaultReactiveDomain() )
id |
Input value name |
selector |
The HTML selector to remove the UI for. By default it is the tag where the ID matches the input, but might need to be adjusted for different inputs. |
session |
The Shiny session to remove the input from |
If the input is a standard shiny input e.g. 'numericInput', then to remove the label as well as the input, set the selector to be 'paste0(":has(> #", id, ")")'
An invisible 'TRUE' value confirming that the input has been removed.
library(shiny) library(shiny.destroy) ui <- fluidPage( numericInput("number", "Select number:", 5, 1, 10), p("Selected number:", textOutput("number_out", inline = TRUE)), actionButton("delete", "Remove input") ) server <- function(input, output, session) { output$number_out <- renderText(input$number %||% "input unavailable") observeEvent( input$delete, removeInput("number", selector = ":has(> #number)") ) } shinyApp(ui, server)
library(shiny) library(shiny.destroy) ui <- fluidPage( numericInput("number", "Select number:", 5, 1, 10), p("Selected number:", textOutput("number_out", inline = TRUE)), actionButton("delete", "Remove input") ) server <- function(input, output, session) { output$number_out <- renderText(input$number %||% "input unavailable") observeEvent( input$delete, removeInput("number", selector = ":has(> #number)") ) } shinyApp(ui, server)
The removal of the named output in a shiny session.
removeOutput( id, selector = paste0("#", id), session = getDefaultReactiveDomain() )
removeOutput( id, selector = paste0("#", id), session = getDefaultReactiveDomain() )
id |
Output value name |
selector |
The HTML selector to remove the UI for. By default it is the tag where the ID matches the output, but might need to be adjusted for different inputs. |
session |
The Shiny session to remove the output from |
An invisible 'TRUE' value confirming that the output has been removed.
library(shiny) library(shiny.destroy) ui <- fluidPage( numericInput("number", "Select number:", 5, 1, 10), p("Selected number:", textOutput("number_out", inline = TRUE)), actionButton("delete", "Remove output") ) server <- function(input, output, session) { output$number_out <- renderText(input$number) observeEvent( input$delete, removeOutput("number_out") ) } shinyApp(ui, server)
library(shiny) library(shiny.destroy) ui <- fluidPage( numericInput("number", "Select number:", 5, 1, 10), p("Selected number:", textOutput("number_out", inline = TRUE)), actionButton("delete", "Remove output") ) server <- function(input, output, session) { output$number_out <- renderText(input$number) observeEvent( input$delete, removeOutput("number_out") ) } shinyApp(ui, server)
To see how the 'shiny.destroy' works, examples are provided within the package.
runDestroyExample(example = NA, ...)
runDestroyExample(example = NA, ...)
example |
The name of the example to run, or |
... |
Additional parameters sent to 'shiny::runExample' |
The following examples are available:
A simple application where the "create" button will load a simple box with a "destroy" button. This highlights the full removal of the module when the button is pressed.
An application that has 2 side by side modules, one using {shiny} to remove the UI and the other using {shiny.destroy} to fully remove the boxes to display the incremental time gain from removing the long-running observers.
The shiny application displayed in the specified location.
runDestroyExample("01_boxes")
runDestroyExample("01_boxes")