有没有办法在 Shiny (R) 中为 renderUI 制作包装函数?

Is there a way to make a wrapper function for renderUI in Shiny (R)?

我需要使用 renderUI 根据另一个输入值创建多个输入选项。我想将 renderUI 中的所有内容作为一个函数包装起来,这样我就可以将其应用于许多类似的输入。这是一个简化的示例(对我有用,但我不想多次重复 renderUI 部分,因为我还有许多其他输入,例如 i1):

library(shiny)
ui <- fluidPage(
    fluidRow(
        selectInput(
            inputId = 'i1',
            label = 'choice 1',
            choices = list(5, 10)
        ),
        uiOutput('o1')
    )
)
server <- function(input, output, session) {
    output$o1 <- renderUI(
        fluidRow(
            sliderInput(
                inputId = 's1',
                label = 'slider 1',
                min = 0, max = as.numeric(input$i1) * 10,
                value = 0.5
            ),
            sliderInput(
                inputId = 's2',
                label = 'slider 2',
                min = 0, max = as.numeric(input$i1) * 100,
                value = 0.5
            )
        )
    )
}
shinyApp(ui = ui, server = server)

问题是,当我尝试将其包装到函数中时,renderUI 创建的输出在我更改输入值时停止更新。这是对我不起作用的代码:

library(shiny)
renderUI_warpper <- function(i){
    renderUI(
        fluidRow(
            sliderInput(
                inputId = 's1',
                label = 'slider 1',
                min = 0, max = as.numeric(i) * 10,
                value = 0.5
            ),
            sliderInput(
                inputId = 's2',
                label = 'slider 2',
                min = 0, max = as.numeric(i) * 100,
                value = 0.5
            )
        )
    )
}
ui <- fluidPage(
    fluidRow(
        selectInput(
            inputId = 'i1',
            label = 'choice 1',
            choices = list(5, 10)
        ),
        uiOutput('o1')
    )
)
server <- function(input, output, session) {
    output$o1 <- renderUI_warpper(input$i1)
}
shinyApp(ui = ui, server = server)

虽然我看不出这样做有什么意义,因为即使你将那个部分移到一个函数中,你仍然必须定义每个 sliderInput,这是一种方法。

关键是你应该包装输入而不是 renderUI,因为你需要反应式表达式才能更新输入,反应式只能在另一个反应式或 render* 函数中工作

library(shiny)

ui <- fluidPage(
  fluidRow(
    selectInput(
      inputId = 'i1',
      label = 'choice 1',
      choices = list(5, 10)
    ),
    uiOutput('o1')
  )
)
server <- function(input, output, session) {
  wrapper <- reactive({
    function(i){
      fluidRow(
        sliderInput(
          inputId = 's1',
          label = 'slider 1',
          min = 0, max = as.numeric(i) * 10,
          value = 0.5
        ),
        sliderInput(
          inputId = 's2',
          label = 'slider 2',
          min = 0, max = as.numeric(i) * 100,
          value = 0.5
        )
      )
      }
  })
  output$o1 <- renderUI(wrapper()(input$i1))
}
shinyApp(ui = ui, server = server)

这是一个可能的选择:

library(shiny)

create_sliders <- function(i) {
  fluidRow(
    column(
      width = 12,
      sliderInput(
        inputId = "s1",
        label = "slider 1",
        min = 0, max = as.numeric(i) * 10,
        value = 0.5
      ),
      sliderInput(
        inputId = "s2",
        label = "slider 2",
        min = 0, max = as.numeric(i) * 100,
        value = 0.5
      )
    )
  )
}

ui <- fluidPage(
  fluidRow(
    selectInput(
      inputId = "i1",
      label = "choice 1",
      choices = list(5, 10)
    ),
    uiOutput("o1")
  )
)
server <- function(input, output, session) {
  output$o1 <- renderUI({
    create_sliders(input$i1)
  })
}
shinyApp(ui = ui, server = server)