1
votes

I'm struggling to code shiny modules that allow one to select an individual stock using a series of two modules.

In the minimal example below :

1) Module 1 selects and returns a reactive subset of stocks

2) Module 2 selects an individual stock based on the subset returned from module 1

The code below throws Error in lapply(obj, function(val) { : object 'display' not found

Please : How to I define the variable 'display' properly so that it is recognised as a reactive expression that may be used as input in Module 2 (i.e. select2_mod)?

Any help with debugging below would be much appreciated.

library(shiny)

stock_vector1 <- c("A", "B", "C", "D", "E", "F") ## Complete vector

### First Module that returns a subset of complete stock vector

select1_modUI <- function(id,stock_vector1){
  ns <- NS(id)
  tagList(
    selectInput(ns('stock_vector2'),
                'Subset of Stocks',
                stock_vector1,
                selected = 'A', 
                multiple = TRUE),
    textOutput(ns('text'))
  )
}

select1_mod <- function(input, output, session,stock_vector1) {
  output$text <- renderText(input$stock_vector2)
  val <- reactive({input$stock_vector2})
  return(val)
}

### Second Module that selects an individual stock

select2_modUI <- function(id,show) {
  ns <- NS(id)
  tagList(
    selectInput(ns('individual_stock'),
                'Select Individual Stock',
                choices = show(),
                selected = 1),
    textOutput(ns('temp'))
  )
}

select2_mod <- function(input, output, session,show) {
  observeEvent(show(), {print(show())})
    output$temp <- renderPrint(input$individual_stock)
  }

# Main app

ui <- fluidPage(
  tabsetPanel(
     tabPanel('Select1',
              h2('Select1'),
              select1_modUI('m1',stock_vector1)),
     tabPanel('Select2',
              h2('Select2'),
              select2_modUI('m2',display))
     )
)

server <- function(input, output, session) {

  display <- callModule(select1_mod,'m1',stock_vector1)
  callModule(select1_mod,'m1',stock_vector1)
  callModule(select2_mod,'m2',display)

}

# Run the app
shinyApp(ui = ui, server = server)
1

1 Answers

1
votes

This should do the trick.

library(shiny)
stock_vector1 <- c("A", "B", "C", "D", "E", "F")

### First Module that returns a subset of complete stock vector
select1_modUI <- function(id){
  ns <- NS(id)
  tagList(
    selectInput(ns('stock_vector2'), 'Subset of Stocks', choices = stock_vector1, selected = "A", multiple = TRUE),
    textOutput(ns('text'))
  )
}

select1_mod <- function(input, output, session){
  output$text <- renderText(input$stock_vector2)
  val <- reactive({input$stock_vector2})
  return(val())
}

### Second Module that selects an individual stock
select2_modUI <- function(id){
  ns <- NS(id)
  tagList(
    selectInput(ns('individual_stock'), 'Select Individual Stock', choices = NULL),
    textOutput(ns('temp'))
  )
}

select2_mod <- function(input, output, session){
  observe({ updateSelectInput(session, 'individual_stock', choices = display())})
  output$temp <- renderPrint(input$individual_stock)
}

# Main app
ui <- fluidPage(
  tabsetPanel(
    tabPanel('Select1',
             h2('Select1'),
             select1_modUI('m1')),
    tabPanel('Select2',
             h2('Select2'),
             select2_modUI('m2'))
))

server <- function(input, output, session) {
  display <<- reactive(callModule(select1_mod, "m1"))
  callModule(select2_mod,'m2')
}

# Run the app
shinyApp(ui = ui, server = server)

There were some minor (but major) errors. When you return a reactive value, you must always use () after the name. Also, instead of passing the options as parameters, I used global variables (that's the reason for <<-) that are automatically passed. I wasn't sure if you know what you were doing with the variable show, which is a reserved word, especially with ().