I have a downloadButton with a downloadHandler, when we want to download the data I have to run a procedure to figure out if there is data to download.
I cannot find a way to Cancel the download handler, the app below prompts us to save some garbage HTML file.
How can we have the downloadHandler exit cleanly?
library(shiny)
ui <- fluidPage(
downloadButton("btn", "Download")
)
server <- function(input, output, session) {
output$btn <- downloadHandler(
filename = function(){
"out.txt"
},
content = function(file){
# this example always fails.
if(TRUE){
print("Sorry, data not written.")
return(NULL)
} else {
writeLines(mtcars, "out.txt")
}
}
)
}
shinyApp(ui, server)
AFAIK, it's not possible to cancel the download once you pressed the button.
Here is a way to download a file without using downloadHandler. It consists in creating an a element, and once you press a button, the file you want to download is converted to base64 encoding, and with the help of shinyjs::runjs the base64 string is given to the href attribute of the a element and the click on the a element is triggered.
library(shiny)
library(shinyjs)
ui <- fluidPage(
useShinyjs(),
checkboxInput("data", "Data"),
actionButton("btn", "Download"),
tags$a(id = "dwnld")
)
server <- function(input, output, session) {
observeEvent(input$btn, {
if(input$data){
tmpFile <- tempfile()
write.table(iris, tmpFile)
b64 <- base64enc::dataURI(file=tmpFile, mime="text/plain")
runjs(sprintf('$("#dwnld").attr("href", "%s").attr("download", "out.txt")', b64))
runjs("$('#dwnld')[0].click();")
}else{
runjs("alert('No data!');")
}
})
}
shinyApp(ui, server)
I wanted to have something similar but in a module. The trick is to have a hidden downloadbutton that is clicked using JS (using shinyjs).
A MWE that implements this using modules looks like this
library(shiny)
download_ui <- function(id) {
ns <- NS(id)
tagList(
shinyjs::useShinyjs(),
actionButton(ns("download"), "Download"),
div(downloadButton(ns("actual_download"), ""), style = "visibility: hidden") # hide this
)
}
download_server <- function(id) {
moduleServer(
id,
function(input, output, session) {
observeEvent(input$download, {
print("Performing some checks...")
check <- TRUE
if (!check) {
showNotification("Abort Download", type = "error")
} else {
showNotification("Start Download", type = "message")
shinyjs::runjs(paste0("document.getElementById('",
session$ns("actual_download"), "').click();"))
}
print("Done Download")
})
output$actual_download <- downloadHandler(
filename = function() "test-file.csv",
content = function(file) {
print("Actually downloading the file")
write.csv(mtcars[1:4, 1:5], file)
}
)
}
)
}
# Include the module in the main ui/server components
ui <- fluidPage(
download_ui("down")
)
server <- function(input, output, session) {
download_server("down")
}
shinyApp(ui, server)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With