I'm having issues with a download button module downloading the correct dataset. Using it once it downloads as you'd expect, but once widget values change, and the download button is re-clicked, it downloads the previously selected variables, almost as if it's caching the values and not updating them. Same thing with the plot/filename titles.
Everything is wrapped in reactive
as necessary, and the plot updates as the values change. Let me know if I'm doing something wrong. Cheers!
Note: issue persists even without usage of modules.
Reprex:
# Load libraries
library(shiny)
library(shinyWidgets)
library(tidyverse)
library(here)
# Load sources
source(here("dwnld buttons.R"))
# Load data
data(mtcars)
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
varSelectInput(inputId = "x_var",
data = mtcars,
label = "Select x var"),
varSelectInput(inputId = "y_var",
data = mtcars,
selected = names(mtcars)[2],
label = "Select y var")
),
mainPanel(
plotOutput(outputId = "plot"),
dwnldButtonUI(id = "download")
)
)
)
server <- function(input, output){
plot1_data <- reactive({
mtcars %>%
select(input$x_var, input$y_var) %>%
rename("x" = input$x_var,
"y" = input$y_var)
})
labels <- reactiveValues()
observeEvent(c(input$x_var, input$y_var), {
labels$title1 <- paste(input$y_var, "vs", input$x_var)
})
output$plot <- renderPlot({
ggplot(data = plot1_data(),
aes(x = x,
y = y))+
geom_point()+
labs(title = labels$title1)
}
)
dwnldButtonServer(id = "download",
file_name = labels$title1,
graph_df = plot1_data()
)
}
shinyApp(ui, server)
### Module ###
dwnldButtonUI <- function(id){
ns <- NS(id)
tagList(
downloadButton(outputId = ns("dwnldBtn"),
label = "")
)
}
dwnldButtonServer <- function(id, file_name, graph_df){
moduleServer(
id,
function(input, output, session){
output$dwnldBtn <- downloadHandler(
filename = function() {
paste(file_name, ".csv", sep = "")
},
content = function(file) {
write.csv(graph_df, file, row.names = FALSE)
}
)
}
)
}
Utilising @Limey's comment, the solution can be extended to include to update both the download data, and filename, after widget values have been changed. This involves passing the reactive
(not its value) to the module, and then accessing its value (not the reactive
itself). See below:
# Here we try and recreate a simplified version of the download button error #
# Load libraries
library(shiny)
library(shinyWidgets)
library(tidyverse)
# library(here)
# Load sources
# source(here("dwnld buttons.R"))
# Load data
data(mtcars)
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
varSelectInput(inputId = "x_var",
data = mtcars,
label = "Select x var"),
varSelectInput(inputId = "y_var",
data = mtcars,
selected = names(mtcars)[2],
label = "Select y var")
),
mainPanel(
plotOutput(outputId = "plot"),
dwnldButtonUI(id = "download")
)
)
)
server <- function(input, output){
plot1_data <- reactive({
mtcars %>%
select(input$x_var, input$y_var) %>%
rename("x" = input$x_var,
"y" = input$y_var)
})
labels <- reactiveValues()
observeEvent(c(input$x_var, input$y_var), {
labels$title1 <- paste(input$y_var, "vs", input$x_var)
})
output$plot <- renderPlot({
ggplot(data = plot1_data(),
aes(x = x,
y = y))+
geom_point()+
labs(title = labels$title1
)
})
labels_title1 <- reactive({labels$title1})
dwnldButtonServer(id = "download",
# File_name and graph_df is passed the reactive, not value
file_name = labels_title1,
graph_df = plot1_data
)
}
shinyApp(ui, server)
# Module UI
dwnldButtonUI <- function(id){
ns <- NS(id)
tagList(
downloadButton(outputId = ns("dwnldBtn"),
label = "")
)
}
# Module server
dwnldButtonServer <- function(id, file_name, graph_df){
moduleServer(
id,
function(input, output, session){
output$dwnldBtn <- downloadHandler(
filename = function() {
# Access the reactive value using ()
paste(file_name(), ".csv", sep = "")
},
content = function(file) {
# Access the reactive value using ()
write.csv(graph_df(), file, row.names = FALSE)
}
)
}
)
}