0
votes

I would like to create a storage to store and retrieve uploaded files even after fileInput is reset.

Basically every time user uploads a file with fileInput, in the future he is forced to click on doneUpload button which resets the fileInput text area and puts his file in the storage (no alternatives please). At this point, user can go back and upload another file which will be put in the storage too.

From my point of view, I have all uploaded files which I can easily retrieve and manipulate. In other words, my question could be translated to: how can I reset fileInput text area without resetting uploaded files?

I have tried creating a reactive value to store uploaded files, however it does not work as I expected.

Here I show you an example to simplify my situation.

library(shiny)

ui<-fluidPage(
  uiOutput("uploadFile"),
  actionButton("doneUpload","Done"),
  tableOutput("exampleTest"))


server<-function(input, output){

  output$uploadFile<-renderUI({
    fileInput("uploadFile", "Upload your file", accept = c(".csv"),placeholder="No files selected")
  })

observeEvent(input$doneUpload,{
    output$uploadFile<-renderUI({
      fileInput("uploadFile", "Upload your file", accept = c(".csv"),placeholder="No files selected")
    })
  })

  reactiveFileUploaded<-reactiveValues(fileUploaded=NULL)

  observe({
    req(input$uploadFile)
    reactiveFileUploaded$fileUploaded<-c(reactiveFileUploaded$fileUploaded,input$uploadFile$datapath)
  })

#Test to verify if the storage has been created. 
#Supposing two files have been uploaded, I retrieve the first one.
output$exampleTest<-renderTable({
    read.csv2(reactiveFileUploaded$fileUploaded[1])
  })

}


shinyApp(ui=ui,server=server)
2

2 Answers

1
votes

Quite Simple, just read the file before clearing the input, after the User has confirmed the Input.

Currently you are reading (and saving) the file the moment the User has selected it, no matter if he wants to upload it or not. Also it seems like you are somehow triggering a loop after selecting a file constantly adding the file to the reactive value.

Also with the datapath you are saving only the filepath not the filecontent, and the filepath also directs to the temp folder so I would recommend changing that routine as well.

But for the most basic functionalities you described the following code should get the job done. (I also added a simple check for content in the filesUploaded variable, so that the error message doesn't appear on start up)

library(shiny)

ui<-fluidPage(
  uiOutput("uploadFile"),
  actionButton("doneUpload","Done"),
  tableOutput("exampleTest"))


server<-function(input, output){

  output$uploadFile<-renderUI({
    fileInput("uploadFile", "Upload your file", accept = c(".csv"),placeholder="No files selected")
  })

  reactiveFileUploaded<-reactiveValues(fileUploaded=c())


  observeEvent(input$doneUpload,{
    req(input$uploadFile)
    reactiveFileUploaded$fileUploaded<-c(reactiveFileUploaded$fileUploaded ,input$uploadFile$datapath)


    output$uploadFile<-renderUI({
      fileInput("uploadFile", "Upload your file", accept = c(".csv"),placeholder="No files selected")
    })
  })



  #Test to verify if the storage has been created. 
  #Supposing two files have been uploaded, I retrieve the first one.
  output$exampleTest<-renderTable({
    if(length(reactiveFileUploaded$fileUploaded)>1)
    read.csv2(reactiveFileUploaded$fileUploaded[1])
  })

}



shinyApp(ui=ui,server=server)
1
votes

Here is a much simpler approach for what you need - Just set multiple = TRUE in fileInput() so that it can accept multiple files at the same time. They can all be read and stored in a reactive in one go using lapply.

library(shiny)

ui <- fluidPage(
  fileInput("files", "Upload", multiple = TRUE),
  actionButton("done", "Done Upload"),
  verbatimTextOutput("test")
)

server <- function(input, output) {

  all_data <- eventReactive(input$done, { # stores data in all files as a list of dataframes
    req(input$files)
    setNames(lapply(input$files$datapath, read.csv), sapply(input$files$name, basename))
  })

  output$test <- renderPrint({
    # all_data()[[1]] # access first file; others can be accessed the same way
    lapply(all_data(), head) # shows first 6 rows of all files with their names
  })
}

shinyApp(ui, server)