Reputation: 65
I have three modules:
numericInput
with value equal to 1.textInput
that is created with renderUI
in the server function. The value is equal to the value of the first 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)
Upvotes: 2
Views: 2896
Reputation: 10375
Your code has some issues:
observe
, you can use reactive
instead because your interest is in the return value (see here)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)
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)
Upvotes: 4