2

I have three modules:

  • The first module creates a numericInput with value equal to 1.
  • The second module creates a textInput that is created with renderUI in the server function. The value is equal to the value of the first module + 1.
  • The third module should do the same as the second module, but with the value equal to the value of the second module + 1.

The choice for textInput and renderUI in the second and third module is deliberate. The code works without the third module, but throws the following error when the third module is included: Error in $: object of type 'closure' is not subsettable. Below is the minimal example code. Help would be much appreciated!

first_module.R

#Define ui
first_module_ui <- function(id) {
  ns <- NS(id)
  
  tagList(numericInput(
    inputId = ns("first_input"),
    label = "First input:",
    value = 1
  ))
}

#Define server logic
first_module_server <- function(input, output, session) {
  return(input)
}

second_module.R

#Define ui
second_module_ui <- function(id) {
  ns <- NS(id)
  
  tagList(uiOutput(outputId = ns("second_input")))
}

#Define server logic
second_module_server <- function(input, output, session, first_module_res) {
    ns <- session$ns
    
    observe({
      second_input <- first_module_res$first_input + 1
      output$second_input <- renderUI({
        disabled(textInput(
          inputId = ns("second_input"),
          label = "Second input:",
          value = second_input
        ))
      })
    })
    return(reactive({second_input}))
  }

third_module.R

#Define ui
third_module_ui <- function(id) {
  ns <- NS(id)
  
  tagList(uiOutput(outputId = ns("third_input")))
}

#Define server logic
third_module_server <- function(input, output, session, second_module_res) {
    ns <- session$ns
    
    observe({
      third_input <- second_module_res$second_input + 1
      output$third_input <- renderUI({
        disabled(textInput(
          inputId = ns("third_input"),
          label = "Third input:",
          value = third_input
        ))
      })
    })
  }

app.R

library(shiny)
library(shinyjs)

# Define UI
ui <- fluidPage(
    
    useShinyjs(),

    # Application title
    titlePanel("Demo"),

    # Sidebar 
    sidebarLayout(
        sidebarPanel(
            first_module_ui("first")
        ),

        mainPanel(
            second_module_ui("second"),
            third_module_ui("third")
        )
    )
)

# Define server logic 
server <- function(input, output, session) {
    
    callModule(first_module_server, "first")
    first_module_res <- callModule(first_module_server, "first")
    
    callModule(second_module_server, "second", first_module_res)
    second_module_res <- callModule(second_module_server, "second", first_module_res)
    
    callModule(third_module_server, "third", second_module_res)
    
}

# Run the application 
shinyApp(ui = ui, server = server)
4

1 回答 1

2

Your code has some issues:

  • you don't need observe, you can use reactive instead because your interest is in the return value (see here)
  • you should make the calculated values to reactives
  • you don't need to call a module twice

Your code didn't work because of how you return the value from the module server function. From the first module, you return the complete input This allows you in the second module to access the values from the input of the first module as you would access it without any modules in the server function from the main app. This means that you don't need brackets to evaluate the reactive, you can just do first_module_res$first_input as you would do with input$first_input.

However, the second module doesn't return input, but a reactive created by you (via reactive({}) in the return value). This now becomes the value that is inputted into the third module and needs to be evaluated there with brackets: second_module_res(). Also note that you directly evaluate the reactive, because it is the only returned value (and not the complete input of the second module).

library(shiny)
library(shinyjs)

#Define ui
first_module_ui <- function(id) {
  ns <- NS(id)
  
  tagList(numericInput(
    inputId = ns("first_input"),
    label = "First input:",
    value = 1
  ))
}

#Define server logic
first_module_server <- function(input, output, session) {
  return(input)
}

#Define ui
second_module_ui <- function(id) {
  ns <- NS(id)
  
  tagList(uiOutput(outputId = ns("second_input")))
}

#Define server logic
second_module_server <- function(input, output, session, first_module_res) {
  ns <- session$ns
  
  second_input <- reactive({
    first_module_res$first_input + 1
  })
  
    output$second_input <- renderUI({
      disabled(textInput(
        inputId = ns("second_input"),
        label = "Second input:",
        value = second_input()
      ))
    })
  return(reactive({second_input()}))
}

#Define ui
third_module_ui <- function(id) {
  ns <- NS(id)
  
  tagList(uiOutput(outputId = ns("third_input")))
}

#Define server logic
third_module_server <- function(input, output, session, second_module_res) {
  ns <- session$ns
  
  third_input <- reactive({
    second_module_res() + 1
  })
  
    output$third_input <- renderUI({
      disabled(textInput(
        inputId = ns("third_input"),
        label = "Third input:",
        value = third_input()
      ))
    })
}

# Define UI
ui <- fluidPage(
  
  useShinyjs(),
  
  # Application title
  titlePanel("Demo"),
  
  # Sidebar 
  sidebarLayout(
    sidebarPanel(
      first_module_ui("first")
    ),
    
    mainPanel(
      second_module_ui("second"),
      third_module_ui("third")
    )
  )
)

# Define server logic 
server <- function(input, output, session) {
  
  first_module_res <- callModule(first_module_server, "first")
  
  second_module_res <- callModule(second_module_server, "second", first_module_res)
  
  callModule(third_module_server, "third", second_module_res)
  
}

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

Edit

You can return a list from a module with several reactives:

library(shiny)
library(shinyjs)

#Define ui
first_module_ui <- function(id) {
  ns <- NS(id)
  
  tagList(numericInput(
    inputId = ns("first_input"),
    label = "First input:",
    value = 1
  ))
}

#Define server logic
first_module_server <- function(input, output, session) {
  return(input)
}

#Define ui
second_module_ui <- function(id) {
  ns <- NS(id)
  
  tagList(uiOutput(outputId = ns("second_input")),
          numericInput(
            inputId = ns("additional_input"),
            label = "Additional input",
            value = 5
          ))
}

#Define server logic
second_module_server <- function(input, output, session, first_module_res) {
  ns <- session$ns
  
  second_input <- reactive({
    first_module_res$first_input + 1
  })
  
  output$second_input <- renderUI({
    disabled(textInput(
      inputId = ns("second_input"),
      label = "Second input:",
      value = second_input()
    ))
  })
  return(list(
    second_input = reactive({second_input()}),
    additional_input = reactive({input$additional_input})
  ))
}

#Define ui
third_module_ui <- function(id) {
  ns <- NS(id)
  
  tagList(uiOutput(outputId = ns("third_input")),
          verbatimTextOutput(outputId = ns("fourth_output")))
}

#Define server logic
third_module_server <- function(input, output, session, second_module_res) {
  ns <- session$ns
  
  third_input <- reactive({
    second_module_res$second_input() + 1
  })
  
  output$third_input <- renderUI({
    disabled(textInput(
      inputId = ns("third_input"),
      label = "Third input:",
      value = third_input()
    ))
  })
  
  output$fourth_output <- renderPrint({
    second_module_res$additional_input()
  })
}

# Define UI
ui <- fluidPage(
  
  useShinyjs(),
  
  # Application title
  titlePanel("Demo"),
  
  # Sidebar 
  sidebarLayout(
    sidebarPanel(
      first_module_ui("first")
    ),
    
    mainPanel(
      second_module_ui("second"),
      third_module_ui("third")
    )
  )
)

# Define server logic 
server <- function(input, output, session) {
  
  first_module_res <- callModule(first_module_server, "first")
  
  second_module_res <- callModule(second_module_server, "second", first_module_res)
  
  callModule(third_module_server, "third", second_module_res)
  
}

# Run the application 
shinyApp(ui = ui, server = server)
于 2020-08-17T22:16:21.677 回答