1

I am new to R shiny and I hope someone can please guide me in the right direction.

I want the user to be able to select one or multiple datasets to download.

Code works when I put the multiple=F in selectInput but when I change it to TRUE, I get the error below:

"Warning: Error in switch: EXPR must be a length 1 vector"

Any help will be greatly appreciated as I am stuck on this for days.

Thank you

library(shiny)
library(openxlsx)

# Define UI for data download app ----
ui <- fluidPage(
  
  # App title ----
  titlePanel("Downloading Data"),
  
  # Sidebar layout with input and output definitions ----
  sidebarLayout(
    
    # Sidebar panel for inputs ----
    sidebarPanel(
      
      # Input: Choose dataset ----
      selectInput("dataset", "Choose a dataset:",
                  choices = c("rock", "pressure", "cars"), multiple=T),
      
      # Button
      downloadButton("downloadData", "Download")
      
    ),
    
    # Main panel for displaying outputs ----
    mainPanel(
      
      tableOutput("table")
      
    )
    
  )
)

# Define server logic to display and download selected file ----
server <- function(input, output) {
  
  # Reactive value for selected dataset ----
  datasetInput <- reactive({
    switch(input$dataset,
           "rock" = rock,
           "pressure" = pressure,
           "cars" = cars)
  })
  
  # Table of selected dataset ----
  output$table <- renderTable({
    datasetInput()
  })
  
  # Downloadable xlsx of selected dataset ----
  output$downloadData <- downloadHandler(
    filename = function() {
      "selected.xlsx"
    },
    content = function(filename) {
      write.xlsx(datasetInput(), file = filename, rowNames = FALSE)
    }
  )
  
}

# Create Shiny app ----
shinyApp(ui, server)
theD
  • 29
  • 5
  • See this https://stackoverflow.com/questions/43916535/download-multiple-csv-files-with-one-button-downloadhandler-with-r-shiny – gdevaux Jul 26 '22 at 12:04
  • @gdevaux Thank you for the link. I am able to download each selected dataset successfully and even tried downloading all to an excel which works. My issue is that I am not able to allow the user to select more than one dataset to download. I want to give them a choice first and then from there download – theD Jul 26 '22 at 12:12
  • Sorry i read a bit too quick. I'm making a proper answer – gdevaux Jul 26 '22 at 12:19

1 Answers1

1

In order to display several datasets, you can create a module (it is like creating a smaller shiny app inside your shiny app that you can call with parameters, just like a function). Here I created a module to display a table, with a dataframe as parameter. For the download, I followed the link I gave you previously.

library(shiny)


#Using module
mod_export_table_ui <- function(id){
  ns <- NS(id)
  tagList(
      tableOutput(ns("table_export"))
  )
}

mod_export_table_server <- function(input, output, session, df_export){
  ns <- session$ns
  output$table_export <- renderTable({
    df_export
  })
}


# Define UI for data download app ----
ui <- fluidPage(
  
  # App title ----
  titlePanel("Downloading Data"),
  
  # Sidebar layout with input and output definitions ----
  sidebarLayout(
    
    # Sidebar panel for inputs ----
    sidebarPanel(
      
      # Input: Choose dataset ----
      selectInput("dataset", "Choose a dataset:",
                  choices = c("rock", "pressure", "cars"), multiple=T),
      
      # Button
      downloadButton("downloadData", "Download")
      
    ),
    
    # Main panel for displaying outputs ----
    mainPanel(
      uiOutput("tables")
    )
  )
)

# Define server logic to display and download selected file ----
server <- function(input, output, session) {

  rv <- reactiveValues()
  
  #List of datasets
  observeEvent(input$dataset, {
    req(input$dataset)
    rv$lst_datasets <- lapply(
          1:length(input$dataset),
          function(i) {
            head(eval(parse(text =input$dataset[i])))
          }
        )
  })
  
  # Module UIs 
  output$tables <- renderUI({
    req(rv$lst_datasets)
    lapply(
      1:length(rv$lst_datasets),
      function(i) {
        mod_export_table_ui(id = paste0("table", i))
      }
    )
  })
  
  # Module Servers
  observeEvent(rv$lst_datasets, {
    req(rv$lst_datasets)
    lapply(
      1:length(rv$lst_datasets),
      function(i) {
        callModule(
          module = mod_export_table_server,
          session = session,
          id = paste0("table", i),
          df_export = rv$lst_datasets[[i]]
        )
      }
    )
  })
  
  output$downloadData <-downloadHandler(
    filename = "Downloads.zip",
    content = function(file){
      withProgress(message = "Writing Files to Disk. Please wait...", {
        temp <- setwd(tempdir())
        on.exit(setwd(temp))
        files <- c()
        
        for(i in 1:length(rv$lst_datasets)){
          writexl::write_xlsx(rv$lst_datasets[[i]],
                              path = paste0("dataset",i, ".xlsx")
          )
          
          files <- c(files, paste0("dataset",i, ".xlsx"))
        }
        zip(zipfile = file, files = files)
      })
    }
  )
  
}

# Create Shiny app ----
shinyApp(ui, server)
gdevaux
  • 2,308
  • 2
  • 10
  • 19
  • Thank you for taking the time and for the guidance. Really appreciate it. I tried running your above code but the download part is not working as it should. Am I missing a package or...? Also I found another thread here on stackoverflow where they are discussing quite a similar issue https://stackoverflow.com/questions/57474489/problem-using-selectinput-to-download-multiple-variables-from-data-in-r-shiny?rq=1 Is there anyway I could also implement this solution to my issue? I tried and still getting same error. Thank you – theD Jul 26 '22 at 15:10
  • What error do you get when you try the download ? – gdevaux Jul 26 '22 at 19:58
  • In my solution the module is only here to display multiple selected tables. If you just want to download them, you don't need the module and can put the `eval(parse(text =input$dataset[i]))` in write_xlsx without displaying an extract of the data. – gdevaux Jul 26 '22 at 20:00
  • For download, you need to install `writexl` package. I'm sorry i forgot to load it in my answer* – gdevaux Jul 26 '22 at 20:01