Allow user to download shiny output in a desired directory


#1

Hello!

In my Shiny app, I run calculations, generate a data frame, and want the user to be able to save (download) it.

My relevant code in ui.R:

textInput("downFile","Save the File:", value = "Results File"),
downloadButton('downFile',"Save File")

My relevant code in server.R:

output$downFile <- downloadHandler(
  filename = function() {
    paste0(input$downFile, " ", Sys.Date(), ".csv") 
  },
  content = function(file) {
      write.csv(MyMainFunction()$mydataframe, file, row.names = FALSE)
  }
)

Everything works. But I have two issues:

  1. If by mistake the user clicks on “Save File” before all the calculations in server.R have been completed, he gets an error (“Failed - Network Error”).
  2. After all the calculations, when the user clicks on the “Save File” button, the file is immediately saved in “Downloads” folder.

Two questions:
Is it possible to make the button invisible until the calculations in my main function (MainFunction) are completed?
How could I allow the user to select a desired folder to download the results to? (as in “Save in…”)

Thank you so much!


#2

Not sure how to change the download behavior, it always works as a “save as” by default for me. I’m not sure (and now curious) this controlled by Shiny or the user’s browser.

For the first part, I handle this in my app by generating the download button server side if there’s data to download and returning nothing if there’s nothing to download

ie:

# server.R

output$download_sim_comparison_link <- renderUI({
  if(is.null(opt_sim_compare_data())){
    return()
  } else {
    downloadLink('download_sim_comparison', p(icon("file-excel-o"), "Export Data"))
  }
})

# ui.R
 uiOutput("download_sim_comparison_link")

I have this embedded in a withSpinner() statement from the shinycssloaders package so it’s obvious why it cant be clicked when the function is executing.


#3

Thank you, that’s nice! For the “save as” - it looks like this is indeed dictated by one’s Chrome setting - and Shiny probably can’t change that. As for hiding the button, I found this really nifty package: shinyjs.

I added this statement to my ui.R:

.... fluidRow(
     useShinyjs()
  everything else as before

And I added these statements on the server side - before the calcs begin:

hide("downFile")

And then this statement after the calculations are finished:

show("downFile")