在另一个模块中使用来自一个 Shiny 模块的变量值

Using variable value from one Shiny module in another module

我有三个模块:

第二个和第三个模块中textInputrenderUI的选择是经过深思熟虑的。该代码在没有第三个模块的情况下工作,但在包含第三个模块时抛出以下错误:Error in $: object of type 'closure' is not subsettable。下面是最小的示例代码。非常感谢您的帮助!

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)

您的代码有一些问题:

  • 您不需要 observe,您可以使用 reactive,因为您感兴趣的是 return 值(参见 here
  • 您应该将计算值设为反应式
  • 你不需要调用一个模块两次

您的代码无法正常工作,因为您 return 来自模块服务器函数的值。从第一个模块,你 return 完整的 input 这允许你在第二个模块中访问第一个模块的 input 中的值,就像你在没有任何模块的情况下访问它一样server 来自主应用程序的功能。这意味着您不需要括号来评估反应式,您可以像使用 input$first_input.

一样执行 first_module_res$first_input

但是,第二个模块不是 return input,而是您创建的反应式(通过 return 值中的 reactive({}))。这现在成为输入到第三个模块的值,需要用括号计算:second_module_res()。另请注意,您直接评估反应式,因为它是唯一的 returned 值(而不是第二个模块的完整 input)。

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)

编辑

您可以 return 来自具有多个反应的模块的列表:

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)