2
votes

I wrote a Shiny app that loads several user-defined csv files as fileInput. The app is designed to plot data from a running measurement and new datapoints are written to the input files about every five minutes. I want to be able to reload all inputs by clicking on an actionButton.

I tried to define the function reading the .csv as eventReactive:

library(shiny)

ui <- fluidPage(
  actionButton(inputId = "update", label = "Reload input files"),
  fileInput(inputId = "file", label = "Choose file"),
  textOutput("test")
)

server <- function(input, output) {
  data <- eventReactive(input$update, {
    mydata <- read.delim(input$file$datapath)
    return(nrow(mydata))
    })
  output$test <- renderText(print(data()))
}

shinyApp(ui = ui, server = server)

When I choose an input file and click the action button, the output is correctly rendered. If I now open the csv file, add additional rows and click the action button again, the output is not updated.

1
The problem is that input$file$datapath links to a temp file which is created when uploading your file. So pressing the update button will read in the temp file again, but this file hasn't changed unlike your original file.TimTeaFan

1 Answers

1
votes

Based on this answer I was able to create a workaround for you problem. As I pointed out in my comment above, the reason why it is not possible to update fileInput with an action button is that, apparently, fileInput creates a temporary file in a temporary directory and the Input$file$datapth links to this temporary file. So you can reload the file with using the action button as often as you like, changes to the orignial file will not be reflected, since the link is pointing to the temporary file. I really don't know why inputFile works with temp files, but using the shinyFiles packages, you can build a workaround. You have one button which gets the real link to your file and load the data in and another button to reload the data. Pressing the load button will reload the original data and all changes to it will be reflected.

library(shiny)
library(shinyFiles)


ui <- fluidPage(
    shinyFilesButton("GetFile", "Choose a file" ,
                     title = "Please select a file:", multiple = FALSE,
                     buttonType = "default", class = NULL),

    actionButton(inputId = "reload", label = "Reload data"),

    tableOutput("test")     
)


server <- function(input,output,session){

    volumes <- getVolumes()

    v = reactiveValues(path = NULL)

    observe({
        shinyFileChoose(input, "GetFile", roots = volumes, session = session)

        if (!is.null(input$GetFile)) {
            file_selected <- parseFilePaths(volumes, input$GetFile)
            v$path <- as.character(file_selected$datapath)
            req(v$path)
            v$data <- read.csv(v$path)
        }
    })

    observeEvent(input$reload, {
        req(v$path)
        v$data <- read.csv(v$path)

    })

    output$test <- renderTable({
        print(v$path)
        if (is.null(v$data)) return()
        v$data
    })

}

shinyApp(ui = ui, server = server)

Update

It is also possible to combine this approach with reactiveFileReader, see example below:

library(shiny)
library(shinyFiles)


ui <- fluidPage(
  shinyFilesButton("GetFile", "Choose a file" ,
                   title = "Please select a file:", multiple = FALSE,
                   buttonType = "default", class = NULL),


  tableOutput("test")     
)


server <- function(input,output,session){

  volumes <- getVolumes()

  v = reactiveValues(path = NULL)

  observe({

    shinyFileChoose(input, "GetFile", roots = volumes, session = session)

      req(input$GetFile)
      file_selected <- parseFilePaths(volumes, input$GetFile)
      v$path <- as.character(file_selected$datapath)
      req(v$path)
      v$data <- reactiveFileReader(1000, session, filePath = v$path, readFun = read.csv, sep = ";")

  })


  output$test <- renderTable({
    print(v$path)
    req(v$data)
    v$data()

  })

}

shinyApp(ui = ui, server = server)