John Smith John Smith - 2 months ago 43
R Question

Shiny Download File based on File Path

I have a file which i generate in shiny
The user clicks a button and the file should download. However nothing happens

The function

export_report
generates the excel file and saves it to a location. The function then passes back the file location to the download handler so it will download the file. The problem seems to be that it isnt being returned correctly. I have tested the function (
export_report
) outside of shiny and it returns everything perfectly so I'm clearly doing something wrong from the shiny perspective.

The file itself is created where it is supposed to be on the server because i can download it within RStudio and see it in the file explorer. Can anyone help

# UI Section
downloadButton("downloadRpt", "Download Report")

# Server Section
output$downloadRpt <- downloadHandler(

filename = function() {
mydf <- report()
dateRange <- input$dates_report
selection <- input$selection
myfile <- export_report (mydf, selection, dateRange)
},
content = function(file) {
file.copy(myfile, file)
}
)


I have seen other examples R Shiny: Download existing file which is what my code is based on

EDIT 1: Adding the export_report function with some fake data to run it

export_report <- function(mydf,selection,dateRange) {

# Template for where the template excel file is stored

myoutputTemplate <- '/home/shiny_tutorials/Save to Database/templates/output_template.xlsx'


start_date <- dateRange[1]
end_date <- dateRange[2]
date_range <- paste(start_date ,end_date, sep = " - " )

# Load workbook the template workbook
wb <- loadWorkbook(myoutputTemplate)

# write to the workbook the data frame
writeWorksheet(wb, mydf, sheet="Details",
startRow=8, startCol=2,
header=FALSE)

# add the the customer the user selected
writeWorksheet(wb, selection, sheet="Details",
startRow=3, startCol=3,
header=FALSE)

# date
writeWorksheet(wb, date_range, sheet="Details",
startRow=5, startCol=3,
header=FALSE)

# Create The file Name
filename <- paste(selection, Sys.Date(), sep = " - ") %>%
paste(.,"xlsx", sep = ".")

# removes the % sign and extra qoutes
filename <- gsub (pattern = '\'|%','', x = filename)

# output directory
myoutput <- paste('/home/shiny_tutorials/Save to Database/output/',
filename, sep = '')

# Save workbook
saveWorkbook(wb, myoutput)

# Return File Path
myoutput

}


To call the function you can use the data below

dateRange <- c("2011-09-23","2016-09-23")
selection = "COMPANY_A"
mydf <- iris
myfile <- export_report(mydf,selection,dateRange)


EDIT 2 I have now managed to get an error out of it. When i
cat(myfile)
in the
filename = function() {
section of the code i get the error after the correct file path has been returned


Warning in rep(yes, length.out = length(ans)) :
'x' is NULL so the result will be NULL
Warning: Error in ifelse: replacement has length zero
Stack trace (innermost first):
1: runApp
Error : replacement has length zero


This error is basically because my file path does not get passed to the segment
myfile
so

if someone can tell me how to get the filepath generated by my function to the server section of the code below, that should fix my problem

content = function(file) {
file.copy(myfile, file)
}

Answer

Thank you to everyone who commented and clarified my thinking a bit on how the download handler works. In the end, i created a new function which split up the export function above The new function i used is called generate_file() which simply returns the file name

generate_file_name <- function(selection) {

  # Create The file Name
  filename <- paste(selection, Sys.Date(), sep = " - ") %>% 
    paste(.,"xlsx", sep = ".")

  # removes the % sign and extra qoutes 
  filename <- gsub (pattern = '\'|%','', x = filename)

  # output directory
  myoutput <-  paste('/home/shiny_tutorials/Save to Database/output/',
                 filename, sep = '')

  # Return File Path
  myoutput

}

Then in the server side

output$downloadRpt <- downloadHandler(
  filename = function() {
    selection <- input$company
    generate_file_name(selection)
  },

  content = function(file) {

    mydf <- report()
    dateRange <- input$dates_report
    selection <- input$company
    export_report(mydf,selection,dateRange)
    myfile <- generate_file_name(selection)
    file.copy(myfile, file)

  }
)

This then finds the newly created file and exports it for the user

Comments