我创建了一个玩具示例,其中弹出一个 textInput() 框供用户输入任何字符串,然后单击添加按钮,弹出一个 selectInput() 框,其中包含带有字符串前缀的字母 a:d。换句话说,如果用户输入“1”,那么通过单击“添加”按钮,会弹出一个 selectInput() 框,其中包含 1a、1b、1c 和 1d 作为选项。我将一个模块用于添加/删除按钮功能,并且该模块调用另一个模块来生成 selectInput() 框。主服务器函数调用添加/删除模块,该模块调用“第一个”模块,该模块生成 selectInput() 框。我将 a() 作为 react 元素传递给添加/删除模块,然后将其传递给“第一个”模块。我只是在 add/remove 模块和“first”模块的函数签名中使用了“...”来获取 a() 到嵌套模块。
这似乎有效,尽管 a() 在到达“第一个”模块时似乎没有反应,这意味着如果我在“a”框中键入不同的字符串,我希望 selectInput( ) 框来动态更改,或者至少当我更改 textInput() 字符串并单击“添加”时,新的 selectInput() 应该反射(reflect)更新后的 textInput() 字符串,但这不会发生。什么会使 selectInput() 选项随着 textInput() 的变化而动态变化?代码如下,谢谢!
library(shiny)
firstUI <- function(id) { uiOutput(NS(id, "first")) }
firstServer <- function(input, output, session, a) {
output$first <- renderUI({
selectInput(session$ns("select"), h4("Select"), paste0(a,letters[1:4]))
})
}
removeFirstUI <- function(id) {
removeUI(selector = paste0('#', NS(id, "first")))
}
addRmBtnUI <- function(id) {
ns <- NS(id)
tags$div(
actionButton(inputId = ns('insertParamBtn'), label = "Add"),
actionButton(ns('removeParamBtn'), label = "Remove"),
hr(),
tags$div(id = ns('placeholder'))
)
}
addRmBtnServer <- function(input, output, session, moduleToReplicate,...) {
ns = session$ns
params <- reactiveValues(btn = 0)
observeEvent(input$insertParamBtn, {
params$btn <- params$btn + 1
callModule(moduleToReplicate$server, id = params$btn, ...)
insertUI(
selector = paste0('#', ns('placeholder')),
ui = moduleToReplicate$ui(ns(params$btn))
)
})
observeEvent(input$removeParamBtn, {
moduleToReplicate$remover(ns(params$btn))
params$btn <- params$btn - 1
})
}
ui <- fluidPage(
addRmBtnUI("addRm"),
textInput("a", label = "a", value = 1, width = '150px') )
server <- function(input, output, session) {
a <- reactive({ input$a })
callModule(
addRmBtnServer, id = "addRm",
moduleToReplicate = list(
ui = firstUI,
server = firstServer,
remover = removeFirstUI
), a = a()
)
}
shinyApp(ui = ui, server = server)
最佳答案
如果你有
a <- reactive({input$a})
您需要将
a
传递给内部(第一个)模块,而不是 a()
。那是因为 a()
表示可观察对象 a
的当前值。这意味着 a()
是不可观察的。在您的代码中,a()
在启动期间在服务器范围内进行评估。那时, a
的值为 1
(在相应的 textInput
中定义的默认值),您将其作为静态对象传递。您可以了解有关 react 值 here 的更多信息。
library(shiny)
firstUI <- function(id) { uiOutput(NS(id, "first")) }
firstServer <- function(input, output, session, a) {
output$first <- renderUI({
selectInput(session$ns("select"), h4("Select"), paste0(isolate(a()),letters[1:4]))
})
}
removeFirstUI <- function(id) {
removeUI(selector = paste0('#', NS(id, "first")))
}
addRmBtnUI <- function(id) {
ns <- NS(id)
tags$div(
actionButton(inputId = ns('insertParamBtn'), label = "Add"),
actionButton(ns('removeParamBtn'), label = "Remove"),
hr(),
tags$div(id = ns('placeholder'))
)
}
addRmBtnServer <- function(input, output, session, moduleToReplicate,...) {
ns = session$ns
params <- reactiveValues(btn = 0)
observeEvent(input$insertParamBtn, {
params$btn <- params$btn + 1
callModule(moduleToReplicate$server, id = params$btn, ...)
insertUI(
selector = paste0('#', ns('placeholder')),
ui = moduleToReplicate$ui(ns(params$btn))
)
})
observeEvent(input$removeParamBtn, {
moduleToReplicate$remover(ns(params$btn))
params$btn <- params$btn - 1
})
}
ui <- fluidPage(
addRmBtnUI("addRm"),
textInput("a", label = "a", value = 1, width = '150px') )
server <- function(input, output, session) {
a <- reactive({ input$a })
callModule(
addRmBtnServer, id = "addRm",
moduleToReplicate = list(
ui = firstUI,
server = firstServer,
remover = removeFirstUI
),
a = a
)
}
shinyApp(ui = ui, server = server)
关于R Shiny : How to pass reactive variables between nested modules,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/46578703/