Lucas Duval
Lucas Duval

Reputation: 317

Capture the for-loop iteration value to create anonymous function for dynamically generated downloadHandler

I'm developing an R Shiny App building a list of graph and I want each data to be downloadable by a click on a button below each graph.

My problem is that the anonymous function created to handle the downloadHandler content args is interpreted only when my button is clicked, and I can't retrieve which button the user pressed on to dispatch the right data to download.

plot_ids is a list of plot_id ["plot_1","plot_2",...]

plot_data is a named list of data ["plot_1"=tibble(),"plot_2"=tibble(),...]

for (plot_id in plot_ids) {
  output[[plot_id]] <- downloadHandler(
      filename = function() {
        paste0("custom_export_", plot_id, ".csv")
      },
      content = function(file){
          write.csv(plot_data[[plot_id]], file, row.names = FALSE)
     }
  )
}

If I generate multiple plot, all the downloadButton & downloadLink are linked to the last generated plot because function(file){...} is interpreted on user click, then plot_id is set to the last value set by the for loop.

I've also tried to generate an anonymous function with as.function(), to set a default parameter function(file,local_plot_id=plot_id), or with a wrapper function.

Upvotes: 0

Views: 41

Answers (1)

Lucas Duval
Lucas Duval

Reputation: 317

I finally found an answer to my problem using the local function

local evaluates an expression in a local environment. It is equivalent to evalq except that its default argument creates a new, empty environment. This is useful to create anonymous recursive functions and as a kind of limited namespace feature since variables defined in the environment are not visible from the outside.

Here's a sample code for local usage in my problem

for (plot_id in plot_ids) {
  output[[plot_id]] <- local({
    local_plot_id <- plot_id
    downloadHandler(
      filename = function() {
        paste0("custom_export_", local_plot_id, ".csv")
      },
      content = function(file){
          write.csv(plot_data[[local_plot_id]], file, row.names = FALSE)
      }
    )
  })
}

Upvotes: 0

Related Questions