0

I am creating a basic Shiny app. It enables the user to select how many groups to compare (in downstream analysis), and then based on this information (i.e. how many groups), fileInput boxes appear to select files for EACH group. However, when uploading files, it doesn't allow the user to upload different files for each fileInput selection. If I select files for the first fileInput section, the next fileInput section won't let me select a new bunch of files. I was using the information from this post:

https://stackoverflow.com/a/19131027/20812519

To dynamically change the amount of file inputs required.


library(shiny)

# Define UI f
ui <- fluidPage(

    # Application title
    titlePanel("Analysis"),

    # Sidebar  
    sidebarLayout(
        sidebarPanel(
          numericInput("group_num", "How many independent variables are you comparing", 2, min = 1, max = 20),
          uiOutput("groups"),
          uiOutput("files")
  
),
        # Show a plot of the generated distribution
        mainPanel(
           uiOutput("table")
        )
    )
)

# Define server logic 
server <- function(input, output) {
  
    output$groups <- renderUI({
      group_num <- as.integer(input$group_num)
      lapply(1:group_num, function(i){
        textInput("group1", "Enter the name of each of your independent groups")
      })
      })
    
      output$files <- renderUI({
        group_num <- as.integer(input$group_num)
        lapply(1:group_num, function(i){
          fileInput("file1", "Select the .csv files from each independent group", multiple = TRUE, accept= ".csv")
        })
    })
      
      
}

# Run the application 
shinyApp(ui = ui, server = server)

I realize it is probably because the file1 ID is not dynamically changing also with each iteration. Also, how can I paste the answers to the text Input section in the main panel?

MM1
  • 478
  • 15

1 Answers1

1

Your diagnosis was correct. All you need to do is construct the IDs of your input widgets in the loop. I think it would also be a good idea to change the label of the inputs to reflect the group to which they refer. Something like this, if I understand you correctly...

library(shiny)

# Define UI f
ui <- fluidPage(
  titlePanel("Analysis"),
  sidebarLayout(
    sidebarPanel(
      numericInput(
        "group_num", 
        "How many independent variables are you comparing", 
        2, 
        min = 1, 
        max = 20
      ),
      uiOutput("groups"),
      uiOutput("files")
    ),
    mainPanel(
      uiOutput("table")
    )
  )
)

server <- function(input, output) {
  output$groups <- renderUI({
    group_num <- as.integer(input$group_num)
    lapply(
      1:group_num, 
      function(i){
        textInput(
          paste0("group", i), 
          paste0("Enter the name of group ", i)
        )
      }
    )
  })
  
  output$files <- renderUI({
    group_num <- as.integer(input$group_num)
    lapply(
      1:group_num, 
      function(i){
        fileInput(
          paste0("file", i), 
          paste0(
            "Select the .csv file for group ", i), 
            multiple = TRUE, 
            accept= ".csv"
          )
    })
  })
}

shinyApp(ui = ui, server = server)

It might also be worth looking into using modules. They're ideal for this sort of "do the same thing many times but with different inputs" type of task.

See this page for more information about Shiny modules.

Limey
  • 10,234
  • 2
  • 12
  • 32
  • Thank you so much, this is exactly what I needed. – MM1 Jul 02 '23 at 23:43
  • Now that I have the multiple files selected, is there a way to rowbind each csv? Could this just be one more row of code inside lapply – MM1 Jul 03 '23 at 00:27
  • That's a separate question. But in brief: Upload all the csv files (perhaps in response to an Upload button). Save the contents of each in a `reactive`. Listen for changes in any of these `reactive`s and then bind together as appropriate. Do you want a separate bound data frame for each of your `fileInpuit`s or a single bound data frame for all `fileInput`s combined? – Limey Jul 03 '23 at 06:29