While working on my (currently WIP) package nebula, I ran into an issue with resetting the fileInput component in Shiny.

In short, nebula allows you to upload a photo of an otolith (fish ear bone), and mark the positions of the growth rings (like in a tree trunk). Once you’ve finished, you can download the positions as a csv file.

The issue I ran into, is once you’ve finished marking your photo, if you want to then start a new photo, you need some way of resetting the fileInput, and removing the current photo. This then allows the user to upload a new photo and repeat the process.

I started implementing this by using the awesome reset function from shinyjs. This almost worked. It reset all the other elements of my app (selectInputs, textInputss etc), but it didn’t reset the fileInput. After the reset button was clicked, the uploaded image was still visible in the UI.

If you dig around online you’ll notice that many people have brought this up on Stack Overflow, Github, and Google Groups. It’s a fairly common problem, across all of web design, not just R/Shiny. While a few solutions were suggested in those posts I had a lot of trouble making any of these work, primarily because of the complexity of my upload function (this is my own fault - I should have been more aggressive in refactoring, but this opened up a different can of worms).

I struggled for a while on how to solve this. Several unsuccessful refactors later, I was still without a solution. Eventually I realised that the reset behaviour I was looking for was essentially a full reload - I want to reset the app back to when it was first loaded in the browser, preserving no state. So I started searching to see if there was someway to reload the Shiny app within Shiny itself.

I searched a bit, and discovered the javascript method history.go. This has the effect of moving across your browsers history. For example, executing history.go(-1) has the effect of going back one page. I discovered that if you use history.go(0), this effectively reloads the page.

Now all I needed was a way to execute this from a shiny button press. There are a variety of ways of doing this, but by far the easiest way is runjs from the shinyjs package. The solution I ended up with was:

For the UI

actionButton("resetAll", "Reset All")

And the server

  observeEvent(input$resetAll, {
    runjs("history.go(0)")
  })

While reloading the entire page is a slightly crude solution, it did mean I was enable to eliminate the rest of the reset code I had for other UI components, and just rely on the full page reload. In addition, from a code perspective, this is an extremely compact and simple solution (~3 lines of code). While it does introduce javascript to the app, I find this is a simpler solution than many of the others online.

While this solution only works for a subset of problems, hopefully others may find it useful if you’re also struggling with the confusing behaviour of resetting fileInput