【问题标题】:How do I make dynamically created inputs in R/Shiny flow like normal inputs in flowLayout?如何在 R/Shiny 流中像 flowLayout 中的普通输入一样动态创建输入?
【发布时间】:2016-12-28 07:19:31
【问题描述】:

我混合了动态创建的输入和通常定义的输入。动态创建的输入就像一个垂直堆叠的大块,其他输入在其周围流动。我如何让它们一起流动?

这重现了问题:

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),'')
      })
    })
  }
)

当前布局:

想要的布局:

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

我想我应该改用这段代码。它在 lapply 内移动 renderUI 以创建多个通用输出(在运行时变化,最多 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),'')
      })
    })
  }
)

【问题讨论】:

    标签: r dynamic input shiny


    【解决方案1】:

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

    devtools::install_github("rstudio/shiny")
    

    Here你可以阅读/了解更多关于insertUIremoveUI

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

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

    selector = paste0('#field', letters[i])
    

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

    现在我们可以将insertUI 包装成for-loop

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

    请注意,我们不需要在客户端添加任何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),'')
          )
        }
      }
    )
    

    编辑:

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

    说,你想生成三个textInput 小部件。您通常可以通过键入

    来执行此操作
    flowLayout(
      textInput('fielda', 'Field A'),
      textInput('fieldb', 'Field B'),   
      textInput('fieldc', 'Field C')
    )
    

    在客户端。您可以通过在服务器端粘贴带有paste0 函数的字符串来做同样的事情,

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

    将其保存在变量中,例如UI,然后解析字符串并最终对其进行评估。

    eval(parse(text = UI))
    

    在下面的示例中,您有 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))
          })
    
      }
    )
    

    【讨论】:

    • 谢谢。这给了我更多的追求途径,但并不是我想要的。此方法将动态 UI 小部件绑定到普通小部件,您只能将小部件插入现有小部件下方;所以 A-1、B-2、C-3、D-4 成对流动。如果动态部分生成了 20 个 UI 小部件,并且没有参考小部件,即只有动态小部件存在怎么办?我的例子可能具有误导性;正如您所提到的,它旨在显示其他项目作为一个块围绕动态小部件流动。我将编辑我的帖子以使其更清晰,但我怀疑我将不得不创建独立输入。
    • 我更新了我的答案,但这只是为了展示另一种可能性,您可以在 flowLayout 中粘贴您想要的所有内容:) 它可以被概括,但是,使用要粘贴的字符串定义变量,然后使用 100x paste0 会很痛苦:)
    • 感谢您的跟进和有趣的解决方案。我也许可以使用它。
    猜你喜欢
    • 2018-11-28
    • 2020-10-14
    • 2014-04-05
    • 2017-01-30
    • 2016-10-26
    • 1970-01-01
    • 2013-01-05
    • 2013-10-08
    • 1970-01-01
    相关资源
    最近更新 更多