How can I disable a downloadButton while server is busy rendering a Rmarkdown report?
The ideal would be to make the button disable only while the server is busy rendering the report, if the server is not busy the downloadButton would enable again.
In the reprex below I tried to use shinyjs::onclick() function to disable the button when it's pressed, but it's only disable when the first Rmarkdown is downloaded by the user. Which is a problem because user can click multiple times until the button gets disabled.
Recipe to the problem:
app.R
library(shiny)
library(shinyjs)
report_path <- tempfile(fileext = ".Rmd")
file.copy("report.Rmd", report_path, overwrite = TRUE)
render_report <- function(input, output, params) {
rmarkdown::render(
input,
output_file = output,
params = params,
envir = new.env(parent = globalenv())
)
}
ui <- fluidPage(
useShinyjs(), # required to use shinyjs
sliderInput("n", "Number of points", 1, 100, 50),
downloadButton("report", "Generate report")
)
server <- function(input, output) {
output$report <- downloadHandler(
filename = "report.html",
content = function(file) {
params <- list(n = input$n)
callr::r(render_report,
list(
input = report_path,
output = file,
params = params
))
}
)
onclick("report", disable("report")) # disable button when it's pressed
}
shinyApp(ui, server)
report.Rmd
---
title: "Dynamic report"
output: html_document
params:
n: NA
---
A plot of `r params$n` random points.
```{r}
plot(rnorm(params$n), rnorm(params$n))
```
My question is based on the following example:
Chapter's link: Mastering Shiny Book
Github's link: Github
Do following:
library(shiny)
library(shinyjs)
report_path <- tempfile(fileext = ".Rmd")
file.copy("report.Rmd", report_path, overwrite = TRUE)
render_report <- function(input, output, params) {
rmarkdown::render(
input,
output_file = output,
params = params,
envir = new.env(parent = globalenv())
)
}
ui <- fluidPage(
useShinyjs(), # required to use shinyjs
sliderInput("n", "Number of points", 1, 100, 50),
downloadButton("report", "Generate report")
)
server <- function(input, output) {
output$report <- downloadHandler(
filename = "report.html",
content = function(file) {
disable("report")
on.exit(enable("report"))
params <- list(n = input$n)
callr::r(render_report,
list(
input = report_path,
output = file,
params = params
))
}
)
}
shinyApp(ui, server)
First disable the button when content generation started, and then use on.exit
to reenable the button. on.exit
makes sure when the function quits, the button is guaranteed to be enabled again, even if an error happens.