Client-side file input value not persistent

The app below contains a file input and a button that prints the value of the file input when clicked.

library(shiny)

shinyApp(
  ui = fluidPage(
    tags$head(
      tags$script(HTML("
  
  $('#get').click(function() {
      console.log($('#file')[0].files)
  })

});"))
    ),
    HTML('
<input id="file" name="file" type="file">
<button id ="get">Show selected file</button>')
  ), 
  server = function(input, output, session) {}
)

When I select a file, the helper text briefly changes to the name of the selected file before reverting to "No file chosen". Clicking the "Show selected file" button returns an empty FileList.

Contrast this behaviour with that of the file input in this JSFiddle. In the JSFiddle, when a file is selected, the helper text changes to display the name of the chosen file. Clicking the button returns a FileList that contains the selected file.

What's causing these differences in the behaviour of the file input?
How can I make the file input value persistent in the client of the Shiny app?

I've taken a look a at the fileInputBinding (line 5821 of www\shared\shiny.js) but can't find anything that would cause the value of the file input to revert to null after the user has selected a file. There is an abortCurrentUpload function but I'm not sure what that's doing.

The reason the file value reverts to "" after selection is due to line 5708 of shiny.js in the onComplete function(/method?):

$(evt.el).val("")

It allows the Shiny:inputchanged event to fire again if the same file is selected consecutively. Please correct me if I'm wrong.

To see why $(evt.el).val("") is needed, I modified my app to include an observer that prints the value of input$file:

library(shiny)

shinyApp(
  ui = fluidPage(
    tags$head(
      tags$script(HTML("
  
  $('#get').click(function() {
      console.log($('#file')[0].files)
  })

});"))
    ),
    HTML('
<input id="file" name="file" type="file">
<button id ="get">Selected file</button>')
  ), 
  server = function(input, output, session) {
    
    observeEvent(input$file, {
      print(input$file)
    })
    
  }
)

Now say the first file I select on app launch is data.xlsx. The value of input$file changes, firing the observer, which prints the value to the console as follows:


                    name  size                                                              type
1 data.xlsx 11992 application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
                                                                            datapath
1 C:\\Users\\owner\\AppData\\Local\\Temp\\RtmpuEATmK/593f7dat42a2a9zc391d1a42/0.xlsx

If I select the same file again, the value is printed to the console again:


                    name  size                                                              type
1 removinglinbreaks.xlsx 11992 application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
                                                                            datapath
1 C:\\Users\\owner\\AppData\\Local\\Temp\\RtmpuEATmK/9958cd63a7a37f0bsd4538bd8/0.xlsx

Now if I take the $(evt.el).val("") out of shiny.min.js and repeat the steps above, the value of input$file is printed to the console when data.xlsx is selected for the first time. However, when I select it again, nothing is printed. So the $(evt.el).val("") workaround was added in order to allow the user to upload the same file twice in a row. This is useful if the user makes changes to the file and wishes to upload the revised version of the file (since modifications to the file don't seem to change the value of the file in the DOM and therefore event handlers like onchange are not responsive to them).

But this workaround makes things a little tricky for me as I am using a third-party plugin that needs to access the value of the file input. It can't do this if the value is always "". What would be the best course of action here? I have thought of a workaround but it requires me to make a slight modification to a particular method of the plugin using $.extend(plugin.prototype, [modified method]). It's not a big change, but I'm worried it could open my project up to bugs.

I don't have any collaborators to think this through with so I would be very grateful if someone with jQuery experience could share their insight/guidance.

This topic was automatically closed 21 days after the last reply. New replies are no longer allowed.