Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Obtuse error on mutually dependent modules with stopifnot() checks #4140

Open
asadow opened this issue Oct 3, 2024 · 1 comment
Open

Obtuse error on mutually dependent modules with stopifnot() checks #4140

asadow opened this issue Oct 3, 2024 · 1 comment

Comments

@asadow
Copy link

asadow commented Oct 3, 2024

Do you think there's a way to improve the error on mutually dependent module servers that use stopifnot() on their inputs? The current error of "object [return name of module server] not found" has confused me more than once.

library(shiny)

moduleA_Server <- function(id, squared) {
  ## A then B in server() causes object 'bmod' not found
  stopifnot(is.reactive(squared))
  
  moduleServer(id, function(input, output, session) {
    observe({
      print(squared())
      })
    list(input_num = reactive(input$input_num))
  })
}

moduleA_UI <- function(id) {
  ns <- NS(id)
  tagList(
    sliderInput(ns("input_num"), "Choose a number", 
                min = 1, max = 10, value = 5),
    textOutput(ns("moduleA_output"))
  )
}

moduleB_Server <- function(id, input_num) {
  ## B then A in server() causes object 'amod' not found
  # stopifnot(is.reactive(input_num))
  
  moduleServer(id, function(input, output, session) {
    squared <- reactive({
      input_num()^2
    })
    
    output$moduleB_output <- renderText({
      paste("Square of number:", squared())
    })
    
    list(squared = squared)
  })
}

moduleB_UI <- function(id) {
  ns <- NS(id)
  tagList(
    textOutput(ns("moduleB_output"))
  )
}

ui <- fluidPage(
  titlePanel("Two-Module App with Interdependency"),
  sidebarLayout(
    sidebarPanel(
      h3("Module A"),
      moduleA_UI("moduleA"),
      h3("Module B"),
      moduleB_UI("moduleB")
    ),
    mainPanel()
  )
)

server <- function(input, output, session) {
  ## A then B
  amod <- moduleA_Server("moduleA", squared = bmod$squared)
  bmod <- moduleB_Server("moduleB", input_num = amod$input_num)
  
  ## B then A
  # bmod <- moduleB_Server("moduleB", input_num = amod$input_num)
  # amod <- moduleA_Server("moduleA", squared = bmod$squared)
}

shinyApp(ui = ui, server = server)

@gadenbuie
Copy link
Member

One approach that works – and that I can't say for sure is The Best Approach – is to use reactiveValue()s that exist outside of the modules and that carry the values from the other modules. This lets you ensure that the reactive exist in the global Shiny app, independently of the two submodules.

server <- function(input, output, session) {
  input_num <- reactiveVal()
  squared <- reactiveVal()

  ## A then B
  # amod <- moduleA_Server("moduleA", squared = squared)
  # bmod <- moduleB_Server("moduleB", input_num = input_num)


  ## B then A
  bmod <- moduleB_Server("moduleB", input_num = input_num)
  amod <- moduleA_Server("moduleA", squared = squared)

  observe(input_num(amod$input_num()))
  observe(squared(bmod$squared()))
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants