How to let download button work with eventReactive?


#1

I want to build a simple app:

  • User provide some parameters that can be glued into sql query.
  • Click Query to see the data.
  • Click Download to download a file.

I tried with the following code. Now the Download button doesn't work (Run the app and click Download).

library(shiny)
library(DBI)
library(glue)

ui <- fluidPage(
    
    titlePanel("Old Faithful Geyser Data"),
    
    sidebarLayout(
        sidebarPanel(
            sliderInput("rows",
                        "Number of rows:",
                        min = 1,
                        max = 50,
                        value = 30)
        ),
        
        mainPanel(
            actionButton("query", "Query"),
            downloadButton("downloadData"),
            tableOutput("table")
        )
    )
)

server <- function(input, output) {
    
    data <- eventReactive(input$query, {
        req(input$rows)
        # get data from database
        con <- dbConnect(RSQLite::SQLite(), ":memory:")
        dbWriteTable(con, "mtcars", mtcars)
        sql <- glue_sql("SELECT * FROM mtcars LIMIT {input$rows}", .con = con)
        df <- dbGetQuery(con, sql)
        dbDisconnect(con)
        df
    })
    
    output$table <- renderTable({
        data()
    })
    
    output$downloadData <- downloadHandler(
        filename = function() {
            paste("data-", Sys.Date(), ".csv", sep="")
        },
        content = function(file) {
            write.csv(data(), file)
        }
    )
}

# Run the application 
shinyApp(ui = ui, server = server)

#2

Your problem is about the input value calculated after pressed on the "Query" button. It can be better to put the database call into a reactive call and let the download handler receive data from there.

server <- function(input, output) {

  db <- reactive({
    req(input$rows)
    con <- dbConnect(RSQLite::SQLite(), ":memory:")
    dbWriteTable(con, "mtcars", mtcars)
    sql <- glue_sql("SELECT * FROM mtcars LIMIT {input$rows}", .con = con)
    df <- dbGetQuery(con, sql)
    dbDisconnect(con)
    df
  })

  data <- eventReactive(input$query, {
    db()
  })

  output$table <- renderTable({
    data()
  })

  output$downloadData <- downloadHandler(
    filename = function() {
      paste("data-", Sys.Date(), ".csv", sep="")
    },
    content = function(file) {
      write.csv(db(), file)
    }
  )
}

#3

@strboul Thanks. I got it. I misunderstand the reactive behavior.

The reactive expression doesn't execute automatically after the input changes. It's the output object that request it to execute.


#4

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