Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.
You can read the original post in its original format on Rtask website by ThinkR here: Mastering file download in shiny
But why does downloadHandler now return an empty file!?
Context
When we start working with {shiny}, we often reach a point where it is necessary to offer the user the option to download a document generated by the application.
This document can be a PDF report, a PNG or JPEG image, or anything else.
The appropriate function for this purpose is shiny::downloadHandler()
, but beyond the (relatively) simple case shown in the documentation’s example, when it comes to using the function in a more complex scenario, it is not uncommon to encounter difficulties, even for an experienced developer.
Therefore, I would like to share with you an approach that we use at ThinkR, which handles both straightforward and more complex cases that we sometimes encounter.
TL;DR:
We will consistently use
file.copy
in thedownloadHandler
Exemple 1
Let’s look at a simple scenario together by starting with the example from the R documentation and making it more “robust”.
Before :
ui <- fluidPage( downloadButton(outputId = "downloadData",label = "Download") ) server <- function(input, output) { # Our dataset data <- mtcars output$downloadData <- downloadHandler( filename = function() { paste("data-", Sys.Date(), ".csv", sep="") }, content = function(file) { write.csv(data, file) } ) } shinyApp(ui, server)
After :
ui <- fluidPage( downloadButton(outputId = "downloadData",label = "Download") ) server <- function(input, output) { local <- reactiveValues(data = mtcars, export_file = NULL ) observeEvent(local$data,{ out <- tempfile(fileext = ".csv") write.csv(x = local$data,file = out) local$export_file <- out }) output$downloadData <- downloadHandler( filename = function() { paste("data-", Sys.Date(), ".csv", sep="") }, content = function(file) { file.copy( from = local$export_file, to = file ) } ) } shinyApp(ui, server)
Do you see the difference? We regain control over the file that will be placed behind the button. It is created here within an observeEvent, making it easy to debug and understand its content.
Example 2
This approach makes complex scenarios more readable :
library(tidyverse) library(shiny) library(flextable) ui <- fluidPage( downloadButton(outputId = "downloadData",label = "Download") ) server <- function(input, output) { local <- reactiveValues(data = mtcars, export_file = NULL ) observeEvent(local$data,{ out <- tempfile(fileext = ".png",pattern = "table_") # write.csv(x = local$data,file = out) local$data %>% flextable::flextable() %>% flextable::save_as_image(path = out) if (file.exists(out)){ local$export_file <- out } else{ local$export_file <- NULL } }) output$downloadData <- downloadHandler( filename = function() { basename(local$export_file) }, content = function(file) { file.copy( from = local$export_file, to = file ) } ) } shinyApp(ui, server)
It’s your turn
This post is better presented on its original ThinkR website here: Mastering file download in shiny
R-bloggers.com offers daily e-mail updates about R news and tutorials about learning R and many other topics. Click here if you're looking to post or find an R/data-science job.
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.