如何在 R/Shiny flow 中动态创建输入,就像 flowLayout 中的普通输入一样?

Mar*_*uss 4 r input dynamic shiny

我混合了动态创建的输入和通常定义的输入。动态创建的输入的行为就像一个大型垂直堆叠块,其他输入围绕其流动。我怎样才能让它们全部流动在一起?

这重现了这个问题:

library(shinydashboard)
shinyApp(
  ui = dashboardPage(
    dashboardHeader(),
    dashboardSidebar(),
    dashboardBody(
      flowLayout(
        uiOutput('input_fields'),
        textInput('fielda','Field A',''),
        textInput('fieldb','Field B',''),
        textInput('fieldc','Field C',''),
        textInput('fieldd','Field D','')
      )
    )
  ),
  server = function(input, output) {
    output$input_fields <- renderUI({
      lapply(1:4, function(i) {
        textInput(paste0('field',i), paste('Field',i),'')
      })
    })
  }
)
Run Code Online (Sandbox Code Playgroud)

当前布局:

所需布局:

编辑:忽略字段 A、B、C、D 小部件。它们仅用于显示其他项目如何换行,但 uiOutput 项目充当一个块。假设所有输入都是动态的。

我想我应该使用这段代码。它将 renderUI 移动到 lapply 内以创建多个通用输出(在运行时变化,最多 10 个),我可以使用同样通用的 uiOutput 语句来引用这些输出。它甚至不会警告 5 个不存在的输出。不完美,但可以了。可能需要添加一个observeEvent,因为我认为它本身不会做出反应。

library(shinydashboard)
shinyApp(
  ui = dashboardPage(
    dashboardHeader(),
    dashboardSidebar(),
    dashboardBody(
      wellPanel(
        flowLayout(
          uiOutput('field1'),
          uiOutput('field2'),
          uiOutput('field3'),
          uiOutput('field4'),
          uiOutput('field5'),
          uiOutput('field6'),
          uiOutput('field7'),
          uiOutput('field8'),
          uiOutput('field9'),
          uiOutput('field10')
        )
      )
    )
  ),
  server = function(input, output) {
    lapply(1:5, function(i) {
      output[[paste0('field',i)]] <- renderUI({
        textInput(paste0('field',i), paste('Field',i),'')
      })
    })
  }
)
Run Code Online (Sandbox Code Playgroud)

Mic*_*jka 5

所有四个动态生成的小部件都被视为一个对象,因为它们包含在一个列表中。因此,定位它们是相当困难的。我能想到的最简单的解决方案是使用insertUI最新闪亮版本的功能,可以使用devtools包安装:

devtools::install_github("rstudio/shiny")
Run Code Online (Sandbox Code Playgroud)

在这里您可以阅读/了解有关insertUI和 的更多信息removeUI

我们必须告诉insertUI它应该在用户界面的何处添加新的小部件,我们通过指定参数selector(它必须是 jQuery 选择器接受的字符串)和参数where(有四个选项指定小部件如何应该相对于选择器)

因此,如果我们想在下面添加一个新的小部件,Field 1我们必须进行设置selector = "#fielda"(我们使用#选择器,因为我们引用的是 ID)。同样,我们Field 2通过设置selector = "#fieldb"等添加另一个小部件。根据您的命名约定,我们可以将其概括为:

selector = paste0('#field', letters[i])
Run Code Online (Sandbox Code Playgroud)

在所有情况下我们也设置where = "afterEnd. 它将把新的小部件放置在参考小部件下方。(没有空间将它们放置在参考小部件上方)

现在我们可以包装insertUIfor-loop

for (i in 1:4) { 
      insertUI(
        selector = paste0('#field', letters[i]), 
        where = "afterEnd",
        ui = textInput(paste0('field',i), paste('Field',i),'')
      )
    }
Run Code Online (Sandbox Code Playgroud)

请注意,我们不需要uiOutput在客户端添加任何内容。

另一个解决方案是dashboardBody在服务器端渲染整个内容,创建动态不同的uiOutputs...这并不令人愉快。


在此输入图像描述

当我们看一下图片时,我们可以看到我是用相反的方式来做的——第一行的名字中的字母大写,第二行的名字中的数字。我希望这不是什么大问题:)


完整示例:

library(shiny)
library(shinydashboard)

shinyApp(
  ui = dashboardPage(
    dashboardHeader(),
    dashboardSidebar(),
    dashboardBody(
      flowLayout(
        textInput('fielda','Field A',''),
        textInput('fieldb','Field B',''),
        textInput('fieldc','Field C',''),
        textInput('fieldd','Field D','')
      )
    )
  ),
  server = function(input, output) {

    for (i in 1:4) { 
      insertUI(
        selector = paste0('#field', letters[i]), 
        where = "afterEnd",
        ui = textInput(paste0('field',i), paste('Field',i),'')
      )
    }
  }
)
Run Code Online (Sandbox Code Playgroud)

编辑:

如果没有参考小部件,那么您还可以flowLayout使用非标准评估在服务器端动态定义。

假设您想生成三个textInput小部件。您通常可以通过输入来完成此操作

flowLayout(
  textInput('fielda', 'Field A'),
  textInput('fieldb', 'Field B'),   
  textInput('fieldc', 'Field C')
)
Run Code Online (Sandbox Code Playgroud)

在客户端。paste0您可以通过在服务器端粘贴带有函数的字符串来执行相同的操作,

        i = 1:3
        UI <- paste0("flowLayout(",
                paste0("textInput(", 
                       "'field", letters[i], "', ",
                       paste0("'Field ", LETTERS[i], "'"), 
                       ")",
                       collapse = ", "),
              ")")
Run Code Online (Sandbox Code Playgroud)

将其保存在变量中,例如,,UI然后解析字符串,最后评估它。

eval(parse(text = UI))
Run Code Online (Sandbox Code Playgroud)

在下面的示例中,您有 15 个动态生成的小部件

在此输入图像描述

完整示例:

library(shiny)
library(shinydashboard)

shinyApp(
  ui = dashboardPage(
    dashboardHeader(),
    dashboardSidebar(),
    dashboardBody(
      wellPanel(
      uiOutput("ui1")
    )
   )
  ),
  server = function(input, output) {

      output[["ui1"]] <- renderUI({
        i = 1:15
        UI <- paste0("flowLayout(",
                paste0("textInput(", 
                       "'field", letters[i], "', ",
                       paste0("'Field ", LETTERS[i], "'"), 
                       ")",
                       collapse = ", "),
              ")")
        # print(UI)
        eval(parse(text = UI))
      })

  }
)
Run Code Online (Sandbox Code Playgroud)

  • 感谢您的后续和有趣的解决方案。我也许可以处理这个问题。 (2认同)