Apparently "shinyjs::hidden()" updates css to "display:none;" which makes the button unclickable. After a small modification, it started working. Thanks @Mikko and @smartse for your input. Below is the working example with single click download using ExtendedTask feature:
library(shiny)
library(bslib)
library(future)
library(promises)
future::plan(multisession)
ui <- fluidPage(
shinyjs::useShinyjs(),
titlePanel("Cars Data"),
textOutput("time"),
bslib::input_task_button("export", "Export", icon = icon("file-export")),
downloadButton("download", "Download", style = "position: absolute; left: -9999px; top: -9999px;"),
)
server <- function(input, output, session) {
# Just to prove UI is not blocked.
output$time <- renderText({
invalidateLater(1000)
format(Sys.time())
})
# Task that prepares a file with the data for download.
export_task <- ExtendedTask$new(function(file) {
promises::future_promise({
data <- mtcars
Sys.sleep(2)
write.csv(data, file)
file
})
}) |> bslib::bind_task_button("export")
# Set up a reusable file for this session's download data.
download_content_path <- tempfile("download_content")
observeEvent(input$export, export_task$invoke(download_content_path))
# Show download button only when file is ready.
observe({
if (export_task$status() == "success") {
showNotification("Your download is ready.")
shinyjs::click("download")
}
})
# Handle download with file prepared by task.
output$download <- downloadHandler(
filename = function() {
paste0("Data-", Sys.time(), ".csv")
},
content = function(file) {
file.rename(export_task$result(), file)
}
)
}
shinyApp(ui = ui, server = server)