如何像在flowLayout中的普通输入一样在R / Shiny流中动态创建输入? [英] How do I make dynamically created inputs in R/Shiny flow like normal inputs in flowLayout?

查看:68
本文介绍了如何像在flowLayout中的普通输入一样在R / Shiny流中动态创建输入?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



这重现了该问题:

 库(shinydashboard)
ShinyApp(
ui = dashboardPage(
dashboardHeader(),
dashboardSidebar(),
dashboardBody(
flowLayout(
uiOutput('input_fields')) ,
textInput('fielda','Field A',''),
textInput('fieldb','Field B',''),
textInput('fieldc','字段C',''),
textInput('fieldd','Field D','')


),
server = function(输入,输出){
output $ input_fields<-renderUI({
lapply(1:4,function(i){
textInput(paste0('field',i),paste( 'Field',i),'')
})
})
}

当前布局:





所需的布局:





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



我想我要改用这段代码。它将renderUI在lapply内部移动,以创建多个通用输出(运行时最多变化10个),我可以使用相同的通用uiOutput语句进行引用。它甚至不会警告5个不存在的输出。虽然不完美,但可以做到。

  library(shinydashboard)$,可能需要添加一个observeEvent。 b $ b ShinyApp(
ui =仪表板页面(
dashboardHeader(),
dashboardSidebar(),
b 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 ),'')
})
})
}


解决方案

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

  devtools :: install_github( rstudio / shiny)



当我们看一看图片时,可以看到我做了相反的处理-名称中的大写字母第一行,第二行名称中的数字。我希望这没什么大不了的:)






完整示例:

 库(发光)
库(发光仪表板)

ShinyApp(
ui = dashboardPage(
dashboardHeader(),
dashboardSidebar(),
dashboardBody(
flowLayout(
textInput('fielda','FieldA','')),
textInput('fieldb','Field B',''),
textInput('fieldc','Field C',''),
textInput('fieldd','Field D ','')


),
服务器=函数(输入,输出){

for(i in 1:4) {
insertUI(
选择器= paste0('#field',字母[i]),
其中= afterEnd,
ui = textInput(paste0('field', i),paste('Field',i),'')

}
}






编辑:



如果没有参考小部件,那么您还可以动态定义

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

  flowLayout(
textInput('fielda','Field A'),
textInput('fieldb','Field B'),
textInput('fieldc','Field C')

在客户端。您可以通过在服务器端使用 paste0 函数粘贴字符串来完成相同的操作,

  i = 1:3 
UI<-paste0( flowLayout(,
paste0( textInput(,
'field,字母[i], ',,
paste0('Field,LETTERS [i],'),
),
crash =,),
) )

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

  eval(parse(text = UI))






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





完整示例:

  li brary(闪亮)
库(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,字母[i],',,
paste0('Field,LETTERS [i],'),
) ,
crash =,),
))
#print(UI)
eval(parse(text = UI))
})

}


I have a mix of dynamically created inputs and normally defined inputs. The dynamically created inputs behave like a large vertically stacked block that the other inputs flow around. How do I make them all flow together?

This reproduces the issue:

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

Current layout:

Desired layout:

Edit: Ignore the Field A,B,C,D widgets. They are just for showing how other items wrap but the uiOutput ones act as one block. Assume all inputs are dynamic.

I think I'm to use this code instead. It moves the renderUI inside the lapply to create multiple generic outputs (varies at runtime, up to 10) which I can reference with equally generic uiOutput statements. It doesn't even warn about the 5 outputs that don't exist. Not perfect but it'll do. Probably need to add in an observeEvent as I don't think it will be reactive on its own.

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

解决方案

All four dynamic generated widgets are treated as one object because they are contained in a list. Therefore it is quite difficult to position them. The easiest solution I can think of is to use insertUI function from the newest shiny version which can be installed using devtools package:

devtools::install_github("rstudio/shiny")

(Here you can read/learn more about insertUI and removeUI)

We have to tell insertUI where it should add new widgets to the user interface, and we do it by specifying the parameter selector (it has to be a string that is accepted by jQuery selector) and the parameter where (there are four choices which which specify how widgets should go relative to the selector)

So if we want to add a new widget under Field 1 we have to set selector = "#fielda" (We use # selector since we are referring to the ID). Similarly, we add another widget under Field 2 by setting selector = "#fieldb" and so on. Following your naming convention we can generalize it to:

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

In all cases we also set where = "afterEnd. It will position new widgets below reference widgets. (There is no space to position them above reference widgets)

Now we can wrap insertUI into a for-loop

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

Note that we don't need to add any uiOutput on the client side.

The other solution would be to render whole dashboardBody on the server side creating dynamically distinct uiOutputs...which wouldn't be pleasant.


When we take a look at the picture we can see that I did it the other way around - capital letters in names in the first row and numbers in names in the second row. It shouldn't be a big deal I hope :)


Full example:

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


EDIT:

If there are no reference widgets then you can also dynamically define flowLayout on the server side using non-standard evaluation.

Say, you want to generate three textInput widgets. You would normally do this by typing

flowLayout(
  textInput('fielda', 'Field A'),
  textInput('fieldb', 'Field B'),   
  textInput('fieldc', 'Field C')
)

on the client side. You can do the same thing by pasting strings with paste0 function on the server side,

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

saving it in a variable, say, UI, then parsing string and finally evaluating it.

eval(parse(text = UI))


In the example below you have 15 dynamically generated widgets

Full example:

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

  }
)

这篇关于如何像在flowLayout中的普通输入一样在R / Shiny流中动态创建输入?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆