我正在尝试模块化一个复杂的Shiny应用程序,我的conditionalPanel
应该只出现给定的输入状态。
在我将所有内容模块化之前,输入和conditionalPanel都在ui.R
中,我可以使用以下内容引用输入:
conditionalPanel("input.select == 'Option one'", p('Option one is selected'))
现在我已经模块化了,访问输入更加复杂。我认为以下是这样做的方法,但它并不是很有效。 (这里我把东西组合成一个独立的脚本):
library(shiny)
## Module code for 'selectorUI' and 'selector'
selectorUI <- function(id) {
ns <- NS(id)
selectizeInput(inputId = ns('select'),
label = 'Make a choice:',
choices = c('Option one', 'Option two'))
}
selector <- function(input, output, session) {
reactive(input$select)
}
## Main app
ui <- shinyUI(fluidPage(
selectorUI('id1'),
conditionalPanel(condition = "output.selected == 'Option one'", p('Option one is selected.'))
))
server <- shinyServer(function(input, output, session) {
output$selected <- callModule(selector, 'id1')
})
shinyApp(ui = ui, server = server)
我认为这应该有效,但事实并非如此 - 只有在主ui部分中对output$selected
进行另一次引用时才有效:
ui <- shinyUI(fluidPage(
selectorUI('id1'),
textOutput('selected'), ## Adding just this one line makes the next line work
conditionalPanel(condition = "output.selected == 'Option one'", p('Option one is selected.'))
))
不幸的是,当然这会产生渲染textOutput('selected')
结果的不良影响。我只能猜测它起作用的原因是因为它以某种方式触发反应,而JavaScript引用本身并没有。
知道如何让这个conditionalPanel正常工作吗?
谢谢..
编辑:原来并不是一个错误:https://github.com/rstudio/shiny/issues/1318。请参阅下面的答案。
但请注意,我实际上更喜欢接受答案中提供的renderUI
解决方案,而不是原来的conditionalPanel
方法。
答案 0 :(得分:6)
调用模块后,selectizeInput
的ID为id1-select
。在javaScript中,有两种访问对象属性的方法:
objectName.property
或objectName['property']
由于-
中ID
我们必须通过字符串引用它,所以第二种方法是可行的。
conditionalPanel
中的条件变为:
input['id1-select'] == 'Option one'
完整示例:
library(shiny)
## Module code for 'selectorUI' and 'selector'
selectorUI <- function(id) {
ns <- NS(id)
selectizeInput(inputId = ns('select'),
label = 'Make a choice:',
choices = c('Option one', 'Option two'))
}
## Main app
ui <- shinyUI(fluidPage(
selectorUI('id1'),
conditionalPanel(condition = "input['id1-select'] == 'Option one'",
p('Option one is selected.'))
))
server <- shinyServer(function(input, output, session) {
})
shinyApp(ui = ui, server = server)
修改强>
这确实有效,但是它是否违反了模块化的概念?您必须知道模块的内部调用该输入的代码&#39;选择&#39;为了构建&#39; id1-select&#39;。
是的,你是对的。
根据这个article,您使用的技巧,即将模块调用分配给所选的输出$,然后通过output.selected
在客户端访问其值应该可以,但它不会。我不知道为什么......这可能是一个错误。 (我有来自github的最新闪亮版本)
我唯一能想到的是使用renderUI
代替conditionalPanel
,如下例所示:
library(shiny)
## Module code for 'selectorUI' and 'selector'
selectorUI <- function(id) {
ns <- NS(id)
selectizeInput(inputId = ns('select'),
label = 'Make a choice:',
choices = c('Option one', 'Option two'))
}
selector <- function(input, output, session) {
reactive(input$select)
}
## Main app
ui <- shinyUI(fluidPage(
selectorUI('id1'),
uiOutput("dynamic1")
))
server <- shinyServer(function(input, output, session) {
output$dynamic1 <- renderUI({
condition1 <- callModule(selector, 'id1') # or just callModule(selector, 'id1')()
if (condition1() == 'Option one') return(p('Option one is selected.'))
})
})
shinyApp(ui = ui, server = server)
答案 1 :(得分:3)
原来它实际上不是一个bug,只是有点棘手。 According to Joe Cheng,
正确 - 默认情况下,如果它们不可见,我们不会计算/渲染输出值。如果我们不计算它们,你就不能在条件下使用它们。
您可以通过设置每次计算输出来更改此行为,您可以在服务器中使用它.R(将
outputId
替换为相应的值):
outputOptions(output, "outputId", suspendWhenHidden = FALSE)
因此,为了解决原始示例的问题,我们只需要将一行添加到服务器函数中:
server <- shinyServer(function(input, output, session) {
output$selected <- callModule(selector, 'id1')
outputOptions(output, 'selected', suspendWhenHidden = FALSE) # Adding this line
})