I have a Shiny app which prints a report once a button is clicked. The report creation happens via the downloadHandler() function.
I would like to have a compulsory input field before the report can be exported; the appropriate Shiny function is validate() (https://shiny.rstudio.com/articles/validation.html).
However, according to the documentation, the validate() function can only be used in reactive() or render() functions:
To use this validation test in your app, place it at the start of any reactive or render* expression that calls input$data.
I do not find a place where I can put this function in my downloadHandler function. Does anybody know how this is possible?
Here is the relevant code part; I want the field "company_name" to be compulsory for the creation of the report.
ui <- fluidPage(
sidebarLayout(
position = "left",
sidebarPanel(
textInput(
inputId = "company_name",
label = "Company name",
value = ""
),
)
)
)
server <- function(input, output) {
output$report <- downloadHandler(
filename = "report.pdf",
content = function(file) {
# Copy the report file to a temporary directory before processing it, in
# case we don't have write permissions to the current working dir (which
# can happen when deployed).
tempReport <- file.path(tempdir(), "report.Rmd")
file.copy("report.Rmd", tempReport, overwrite = TRUE)
dir.create(file.path(tempdir(),"www"))
file.copy("www", file.path(tempdir()), recursive=TRUE)
# Set up parameters to pass to Rmd document
params <- list(company_name = input$company_name)
# Knit the document, passing in the `params` list, and eval it in a
# child of the global environment (this isolates the code in the document
# from the code in this app).
rmarkdown::render(tempReport, output_file = file,
params = params,
envir = new.env(parent = globalenv())
)
}
)
}
The problem is that a downloadButton is an input widget and validate is supposed to be used with outputs.
My workaround would be to hide (or disable) the downloadButton if your requirements for downloading are not met. This can be done with shinyjs, which allows you to hide or disable buttons by id.
library(shiny)
ui <- fluidPage(
shinyjs::useShinyjs(),
textInput("text", "content", "", placeholder = "please insert something"),
shinyjs::hidden(downloadButton("download"))
)
server <- function(input, output, session) {
output$download <- downloadHandler(
filename = "file.csv",
content = function(file) {
write.csv(data.frame(content = input$text), file)
}
)
observeEvent(input$text, {
if (input$text == "")
shinyjs::hide("download")
else
shinyjs::show("download")
})
}
shinyApp(ui, server)
Replace hide/show/hidden with enable/disable/disabled to show the button all the time but make it unclickable whenever input$text is empty.
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