Search code examples
rshinyenvironment-variablesshiny-reactivity

How to send reactive values from Shiny App into global environment for review?


The below example code uses a module structure to pass values from the main server to two modules mod1 and mod2 where the values are manipulated and passed back and forth between the modules. This is for learning purposes.

I use common <- reactiveValues() in the main server and then assign values to common$xyz inside the modules, which is then accessible inside all of the modules. The code works as intended: when running, the top of the Shiny window shows a base dataframe df, the user uses a slider input to specify the value to multiply the base df by with results rendered in the 2nd table, the 3rd table adds 10 to each of the second table's values and sends it's column A back to the 2nd table to be appended to the end of the 2nd table, and then the 2nd table's last column is multiplied by 100 and sent back to the 3rd table to be appended to its end. This is for practicing sending data back and forth between modules.

My question: how can I send the complete common reactive object to the global environment for testing and review purposes? As I build out this code I need to have a complete view into how this common object is evolving.

In the below code I tried this using: oe1 <- reactive({common}) and observeEvent(oe1(),{common.R <<- oe1()}) in the main server section, but all I get back is:

> common.R
<ReactiveValues> 
  Values:    colA_mod2, df, mod1_dat, mod2_table, svc 
  Readonly:  FALSE  

which doesn't tell me much. I would like to see the entire common object with all values and elements that are housed in it. I would rather retrieve the object in the manner I just described rather than seeing it scroll by the R Studio console when using a print() statement, because the common object I am working towards will be very large.

Code:

library(shiny)
library(DT)

mod1_ui <- function(id) {
  ns <- NS(id)
  DTOutput(ns("tbl"))
}

mod1_server <- function(id, common) {
  moduleServer(id, function(input, output, session) {
    new_dat <- reactive({
      df <- common$df
      svc <- common$svc()
      df * as.numeric(svc)
    })
    
    observe({
      common$mod1_dat <- new_dat()
      common$colA_mod2 <- common$mod2_table$A
    })
    
    output$tbl <- renderDT({
      dat <- new_dat()
      dat$colA_mod2 <- common$colA_mod2 
      dat
    })
  })
}

mod2_ui <- function(id) {
  ns <- NS(id)
  DTOutput(ns("tbl"))
}

mod2_server <- function(id, common) {
  moduleServer(id, function(input, output, session) {
    output$tbl <- renderDT({
      mod1_dat <- common$mod1_dat
      dat <- data.frame(mod1_dat + 10) 
      if (!is.null(common$colA_mod2)) {
        dat$colA_mod2_mod1 <- common$colA_mod2 * 100
      }
      common$mod2_table <- dat
      dat
    })
  })
}

ui <- fluidPage(
  mainPanel(
    DTOutput("table"),
    sliderInput("svc", "", min = 0, max = 10, value = 1),
    mod1_ui("mod1"),
    mod2_ui("mod2")
  )
)

server <- function(input, output, session) {
  common <- reactiveValues(df = data.frame(A = 1:2, B = 3:4))
  output$table <- renderDT({datatable(common$df)})
  common$svc <- reactive(input$svc)
  mod1_server("mod1", common)
  mod2_server("mod2", common)
  
  oe1 <- reactive({common})
  observeEvent(oe1(),{common.R <<- oe1()})
  
}

shinyApp(ui, server)

Solution

  • Have you tried using browser()? If you haven't, what it does is that, when you run your Shiny app on RStudio, it pauses your Shiny app at the place you put the browser() function, then gives you access to the console inside the current environment in which your Shiny app is running, thus allowing you to directly check the objects you need. Then, you can resume the app using the controls above the console. I use this all the time by placing browser() at the beginning of reactive({}) calls to check if data is correct before plotting or further processing, or to quickly test plots using values from inputs.