When an error occurs within a downloadHandler
object, the app will still pop up a download window. Generally the only indication that an error has occurred is that the default filename and type are not right in the pop-up. In this example:
ui <- fluidPage(
downloadLink("downloadData", "Download")
)
server <- function(input, output) {
data <- mtcars
output$downloadData <- downloadHandler(
filename = function() {
paste("data-", Sys.Date(), ".csv", sep="")
},
content = function(file) {
stop()
write.csv(data, file)
}
)
}
shinyApp(ui, server)
The stop()
here simulates an error. When running the script, the only indication that the widget did not work correctly is that the default filename is downloadData.htm
instead of data-[date]-.csv
.
Is there a way to catch this error and prevent the download window from launching?
This is a modification of @Eliot Dixon's answer that removes the requirement to know in advance if the downloadHandler
logic will fail. The key is to have an always-hidden downloadButton
and an always-visible actionButton
. When the actionButton
is clicked, run the complicated logic. If it succeeds, save the resulting data to a reactiveVal
and then use shinyjs::click()
to simulate clicking on the real, but hidden, downloadButton
.
library(shiny)
library(shinyjs)
ui <- fluidPage(
useShinyjs(),
selectInput("dataExists", "Data exists", choice = c("TRUE", "FALSE")),
conditionalPanel("false", downloadButton("downloadData", "Download")),
actionButton("click", "Download")
)
server <- function(input, output) {
computed_data <- reactiveVal()
observeEvent(input$click, {
# Put all content logic here.
# If it fails, showNotification.
# If it succeeds, store result and click button.
if(input$dataExists == "FALSE"){
showNotification("Data error.")
} else {
computed_data(mtcars)
click("downloadData")
}
})
output$downloadData <- downloadHandler(
filename = function() {
paste("data-", Sys.Date(), ".csv", sep="")
},
content = function(file) {
write.csv(computed_data(), file)
}
)
}
shinyApp(ui, server)