insertUI 中的 R 闪亮动态 UI

Wal*_*ity 5 r shiny

我有一个 Shiny 应用程序,我想在其中使用操作按钮添加 UI 元素,然后让插入的 ui 成为动态的。

这是我当前的 ui 文件:

library(shiny)

shinyUI(fluidPage(
  div(id="placeholder"),
  actionButton("addLine", "Add Line")
))
Run Code Online (Sandbox Code Playgroud)

和服务器文件:

library(shiny)

shinyServer(function(input, output) {
  observeEvent(input$addLine, {
    num <- input$addLine
    id <- paste0("ind", num)
    insertUI(
      selector="#placeholder",
      where="beforeBegin",
      ui={
         fluidRow(column(3, selectInput(paste0("selected", id), label=NULL, choices=c("choice1", "choice2"))))
      })
  })

})
Run Code Online (Sandbox Code Playgroud)

如果choice1在特定的 ui 元素中选择了 ,我想textInput在行中添加一个。如果choice2在 ui 元素中选择了 ,我想添加一个numericInput.

虽然我通常了解如何创建响应用户输入而改变的反应值,但我不知道在这里做什么,因为我不知道如何观察尚未创建的元素并且我不知道名称的。任何帮助将不胜感激!

tho*_*hal 11

代码

这可以通过模块轻松解决:

library(shiny)

row_ui <- function(id) {
  ns <- NS(id)
  fluidRow(
    column(3, 
           selectInput(ns("type_chooser"), 
                       label = "Choose Type:", 
                       choices = c("text", "numeric"))
    ),
    column(9,
           uiOutput(ns("ui_placeholder"))
    )
  )
} 

row_server <- function(input, output, session) {
  return_value <- reactive({input$inner_element})
  ns <- session$ns
  output$ui_placeholder <- renderUI({
    type <- req(input$type_chooser)
    if(type == "text") {
      textInput(ns("inner_element"), "Text:")
    } else if (type == "numeric") {
      numericInput(ns("inner_element"), "Value:", 0)
    }
  })

  ## if we later want to do some more sophisticated logic
  ## we can add reactives to this list
  list(return_value = return_value) 
}

ui <- fluidPage(  
  div(id="placeholder"),
  actionButton("addLine", "Add Line"),
  verbatimTextOutput("out")
)

server <- function(input, output, session) {
  handler <- reactiveVal(list())
  observeEvent(input$addLine, {
    new_id <- paste("row", input$addLine, sep = "_")
    insertUI(
      selector = "#placeholder",
      where = "beforeBegin",
      ui = row_ui(new_id)
    )
    handler_list <- isolate(handler())
    new_handler <- callModule(row_server, new_id)
    handler_list <- c(handler_list, new_handler)
    names(handler_list)[length(handler_list)] <- new_id
    handler(handler_list)
  })

  output$out <- renderPrint({
    lapply(handler(), function(handle) {
      handle()
    })
  })
}

shinyApp(ui, server)
Run Code Online (Sandbox Code Playgroud)

解释

模块是一段模块化的代码,您可以随意重用它,而无需担心唯一名称,因为模块会在namespaces.

一个模块由两部分组成:

  1. 一个UI函数
  2. 一个server函数

它们与 normalUIserverfunctions非常相似,但需要注意以下几点:

  • namespacing:在服务器中,您可以UI像往常一样从 访问元素,例如input$type_chooser。但是,在这UI部分,您必须namespace通过 using来处理元素,NS它返回一个函数,您可以在其余代码中方便地使用该函数。为此,该UI函数采用一个参数id,该参数可以视为此模块的任何实例的(唯一)命名空间。该元素ids在模块内必须是唯一的,并且由于命名空间,它们在整个应用程序中也将是唯一的,即使您使用模块的多个实例。
  • UI: 因为你UI是一个函数,它只有一个 返回值,tagList如果你想返回多个元素(这里不需要),你必须将元素包装在 a 中。
  • server:你需要session参数,否则它是可选的。如果您希望您的模块与主应用程序进行通信,您可以传入一个(反应式)参数,您可以像往常一样在您的模块中使用该参数。类似地,如果您希望主应用程序使用模块中的某些值,您应该返回反应式,如代码所示。如果你想UI从你的服务器函数中创建元素,你还需要命名它们,你可以通过session$ns如图所示访问命名空间函数 。
  • usage:要使用您的模块,您可以UI通过使用唯一的id. 然后您必须调用callModule以使服务器逻辑正常工作,在那里您传递相同的id. 此调用的返回值是returnValue您的模块服务器功能的 ,并且可以被起诉以使用来自模块内的值,也可以在主应用程序中使用。

这简要地解释了模块。可以在这里找到一个非常好的教程,它更详细和完整地解释了模块