Update downloadHandler filename Using a textInput() value

Hello,
I want to create a downloadHandler() function that takes the output value of a textInput() field and uses it as the "Save As" file name when the user clicks the download button.

Here's some code for a reproducible example. Note the report name text box. I want to create a function that effectively observes the change in the text input and passes it to the downloadHandler, so that when the user clicks the download button, it is customized with the textInput() value entered.

Any guidance is appreciated!

##  ----- LOAD REQUIRED PACKAGES -----
library(shiny)
library(DT)
library(ggplot2)

## ------ LOAD EXAMPLE DATA ------

cars = mtcars

## -----THE UI -----

ui <- fluidPage(
  titlePanel("Car Data Report"),
  fluidRow(
    column(4,
    textInput("reportText", label="Report Name", value="Enter Report Name", width=NULL))
  ),
  
  # Create a new Row in the UI for selectInputs
  fluidRow(
    column(4,
           selectInput("cyl",
                       "Cylinders:",
                       c("All",
                         unique(sort(as.character(cars$cyl)))))
    ),
    column(4,
           selectInput("gear",
                       "Gears:",
                       c("All",
                         unique(as.character(cars$gear))))
    ),
    column(4,
           selectInput("carb",
                       "Carburators:",
                       c("All",
                         unique(as.character(cars$carb))))
    )
  ),
  # Create a new row for the table.
  
  DT::dataTableOutput("dt"),
  
  # Create a new row for the download button
  
  downloadButton(outputId = "download_filtered",
                 label = "Download Filtered Data")
)
## ---- END UI ----

## ----- START SERVER -----

server = function(input, output){
  
  ## Create a reactive DF function for filters:
  
  reactiveDF = reactive({
    cardata <- cars
    
    # conditionals 
    
    if (input$cyl != "All") {
      cardata <- cardata[cardata$cyl == input$cyl, ]
    }
    if (input$gear != "All") {
      cardata <- cardata[cardata$gear == input$gear, ]
    }
    if (input$carb != "All") {
      cardata <- cardata[cardata$carb == input$carb, ]
    }
    
    # display the filtered data
    cardata
       
  })
  
  ## Output Datatable -------
  output$dt <- DT::renderDataTable(datatable({
    reactiveDF()
  }))
  
## ---- DOWNLOADHANDLER

  ## THIS IS WHERE I AM STUCK.  
 ## How do I make this "reactive" so that it "reads" the text input and passes it to the filename?
  output$download_filtered <-
    downloadHandler(
      filename = "filtered_report.csv",
      content = function(file){
        write.csv(reactiveDF(),file)
      }
    )
}

shinyApp(ui,server)

output$download_filtered <-
  downloadHandler(
    filename = function() {
      repname <- "filtered_report.csv"
      if (isTruthy(input$reportText)) {
        if (input$reportText != "Enter Report Name") {
          repname <- input$reportText
        }
      }
      repname
    },
    content = function(file) {
      write.csv(reactiveDF(), file)
    }
  )
1 Like

@nirgrahamuk - this worked perfectly. The only missing piece here is that your code failed to update the entire download name to include the file output (".csv") - but that was easily remedied by tagging that back on using paste():

output$download_filtered <-
  downloadHandler(
    filename = function() {
      repname <- "filtered_report.csv"
      if (isTruthy(input$reportText)) {
        if (input$reportText != "Enter Report Name") {
          repname <- paste(input$reportText, ".csv", sep="")
        }
      }
      repname
    },
    content = function(file) {
      write.csv(reactiveDF(), file)
    }
  )

To elaborate for the good of the community, isTruthy() tests the condition so that if the textinput() value is TRUE, it will return that value as entered.

repname is the report name, which is set to a default of "filtered_report.csv". If the input$reportText value is something different than "Enter Report Name", it will equal the custom text entered.

Many thanks for your solution.

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.

If you have a query related to it or one of the replies, start a new topic and refer back with a link.