【问题标题】:R Shiny modules with conditionalPanel and reactives带有条件面板和反应器的 R Shiny 模块
【发布时间】:2016-08-26 04:43:44
【问题描述】:

我正在尝试模块化一个复杂的 Shiny 应用程序,我有一个 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 引用本身不会。

知道我应该如何让这个条件面板正常工作吗?

谢谢你..

编辑:原来实际上不是一个错误:https://github.com/rstudio/shiny/issues/1318。请参阅下面我自己的答案。

但还要注意,我实际上比我原来的conditionalPanel 方法更喜欢接受答案中给出的renderUI 解决方案。

【问题讨论】:

    标签: r module shiny


    【解决方案1】:

    调用模块后selectizeInput的ID为id1-select。在 javaScript 中有两种访问对象属性的方法:

    objectName.propertyobjectName['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)
    

    编辑:

    这确实有效,但它不违反模块化的概念吗?您必须知道模块内部调用输入“select”的代码才能构造“id1-select”。

    是的,你是对的。

    根据这个article,您使用的技巧,即将一个模块调用分配给 output$selected 然后通过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)
    

    【讨论】:

    • 这确实有效,但它不违反模块化的概念吗?您必须知道模块内部调用输入“select”的代码才能构造“id1-select”。
    • 我认为这确实是一个错误。我在github.com/rstudio/shiny/issues/1318 提交了一个更简单的示例。实际上我更喜欢renderUI 解决方案,因为conditionalPanel 依赖display: none 样式来隐藏内容,而renderUI 方法只给出一个空的div。谢谢你的报道。
    【解决方案2】:

    事实证明它实际上不是一个错误,只是有点棘手。 According to Joe Cheng,

    是的——默认情况下,如果输出值不可见,我们不会计算/渲染它们。如果我们不计算它们,你就不能在条件下使用它们。

    您可以通过设置每次计算的输出来更改此行为,您可以在 server.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
    })
    

    【讨论】:

    • 在我的闪亮版本中,output 根本无法从 ui 部分访问,因此 @Michal Majka 的方法是唯一的方法。
    • 这个答案中添加的行给出的示例适用于闪亮版本1.1.0
    猜你喜欢
    • 2014-11-18
    • 2016-06-04
    • 2016-08-14
    • 2020-02-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多