David
David

Reputation: 10152

ShinyModules with "global" reactive values

I have a largish shiny app, where multiple elements change reactiveVals. Now I want to port the app to use shiny modules to be able to test it more appropriately. But I am not able to access the reactive values that are defined inside the server function.

MWE

A simple app that highlights my thought process so far is this counter app. The app consists two modules: counter and display

The main part of the app is a "central" reactive value called counter_reactive, which holds the current count. This value is set by the counter and read by the display module elements.

library(shiny)

######################
# Counter Module
counter_UI <- function(id) {
  ns <- NS(id)
  tagList(
    actionButton(ns("button"), "Increase Count")
  )
}
counter <- function(input, output, session) {
  observeEvent(input$button, {
  counter_reactive(counter_reactive() + 1)
    cat("Increase Counter by 1 to", counter_reactive(), "\n")
  })
}

######################
# Display Module
display_UI <- function(id) {
  ns <- NS(id)
  tagList(
    verbatimTextOutput(ns("text_output"))
  )
}
display <- function(input, output, session) {
  observe({
    cat("Print Value of Counter\n")
    output$text_output <- renderText(sprintf("Counter is now %i", counter_reactive()))
  })
}

######################
# Rest of the Shiny App
ui <- fluidPage(
  counter_UI("counter1"),
  display_UI("display1")
)

server <- function(input, output, session) {
  # Note that counter_reactive is defined inside the "global" server function, 
  # as multiple modules should read and write to it. 
  counter_reactive <- reactiveVal(0)
  
  callModule(counter, "counter1")
  callModule(display, "display1")
}

shinyApp(ui, server)

However, this app throws the error Warning: Error in counter_reactive: could not find function "counter_reactive". Any ideas how to get/change the reactive value inside the module?

Upvotes: 0

Views: 448

Answers (1)

David
David

Reputation: 10152

Rubber-Ducky-Debugging (aka SO-Question Writing Debugging) to the rescue, this works:

Simply passing the reactive value to the functions like so

counter <- function(input, output, session, counter_reactive) {
  observeEvent(input$button, {
    counter_reactive(counter_reactive() + 1)
    cat("Increase Counter by 1 to", counter_reactive(), "\n")
  })
}

display <- function(input, output, session, counter_reactive) {
  observe({
    cat("Print Value of Counter\n")
    output$text_output <- renderText(sprintf("Counter is now %i", counter_reactive()))
  })
}

server <- function(input, output, session) {
  
  counter_reactive <- reactiveVal(0)
  
  callModule(counter, "counter1", counter_reactive)
  callModule(display, "display1", counter_reactive)
}

Upvotes: 1

Related Questions