How do I make dynamically created inputs in R/Shiny flow like normal inputs in flowLayout?

前端 未结 1 1681
一个人的身影
一个人的身影 2021-01-14 03:35

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 fl

1条回答
  •  再見小時候
    2021-01-14 04:10

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

    0 讨论(0)
提交回复
热议问题