在对Shiny :: renderUI的同一调用中,如何隔离一个输入与另一个输入?

时间:2018-08-28 21:47:08

标签: r shiny

我有许多输入都存在于使用conditionalPanel在服务器端创建的同一renderUI中。我不能将其移至用户界面,因为某些部分使用了反应对象。

我想做的是让一个输入确定另一输入的默认值。但是,由于这两者都存在于对renderUI的同一调用中,因此它创建了循环依赖项,这使我无法选择除前一个输入的默认选项之外的任何内容。考虑以下示例app.R文件:

library(shiny)

key <- c("a" = 1, "b" = 2, "c" = 3, "d" = 4)

ui <- fluidPage(
    uiOutput("inputs")
)

server <- function(input, output) {
  output$inputs <- renderUI(
    tagList(
      selectInput("input1", "Input 1:", letters[1:4]),
      textInput("input2", "Input 2:", rval())
    )
  )

  rval <- reactive(key[input$input1])

}

shinyApp(ui = ui, server = server)

我在全局环境中定义key(在应用程序中,这是从全局中的.yaml文件读取的),然后uiOutput向用户显示所有输入。我们可以看到input2的默认值取决于为input1选择的内容。发生的情况是input1触发了rval()的更改,进而触发了input2的更改。还行吧。但是,由于input1input2是在对renderUI的同一调用中呈现的,因此input1变得依赖于它自己,因此只要用户在其中选择另一个选项,它就会重置为默认值。下拉菜单。

我再次这样编码,因为两个输入在我正在使用的实际应用程序中存在于同一conditionalPanel中(尽管在本示例中不是)。

我尝试用selectInput(...)包围isolate(),但这是行不通的。

如何将两个输入保留在相同的renderUI中,但允许用户更改input1而又不必依赖于自身并进行重置?

1 个答案:

答案 0 :(得分:2)

您可以使用observeEvent(iunputs$input1, ...)updateTextinput使input2保持最新。使用这种方法的优点是您的UI不必经常重新渲染。

library(shiny)

key <- c("a" = 1, "b" = 2, "c" = 3, "d" = 4)

ui <- fluidPage(
  uiOutput("inputs")
)

server <- function(input, output, session) {
  output$inputs <- renderUI({
    tagList(
      selectInput("input1", "Input 1:", letters[1:4]),
      textInput("input2", "Input 2:", "placeholder")
    )
  })

  observeEvent(input$input1, {
    mapped_input <- key[[req(input$input1)]]
    updateTextInput(session, "input2", value = mapped_input)
  })

}

shinyApp(ui = ui, server = server)

req确保仅在updateTextInput已经渲染的情况下调用output$inputs

我意识到在某些情况下,updateXXX函数不足以呈现动态输入。在这种情况下,最好是在单独的renderUI语句中生成UI,这样就不再需要循环性了。

注意:我不知道conditionalPanel是如何使必须使用renderUI的。如果您正在寻找在代码中使用抽象的方法,请改用Shiny Modules