det
det

Reputation: 5232

Disable downloadButton after renderUI

I want to change downloadButton label dynamically (in response to save_format) and I would like for downloadButton to be disabled at first. I've tried to follow advice given in https://community.rstudio.com/t/renderui-to-create-an-input-thats-pre-disabled/59382 but it seems it only blurs downloadButton but still I can click on it. Here is example:

library(shiny)

ui <- navbarPage(
    
    title = "TEST",
    
    tabPanel(
        
        "EXAMPLE",
        
        bootstrapPage(  
            
            absolutePanel(
                
                uiOutput(outputId = "download_ui"),
                selectInput(
                    inputId = "save_format",
                    label = NULL,
                    choices = c("format1", "format2"),
                    selected = "csv"
                )
            )
        )
    )
)

server <- function(input, output) {

    output$download_ui <- renderUI({
        
        downloadButton(
            outputId = "download",
            label = str_c("Download ", input$save_format),
            disabled = ""
        )
    })
    
    output$download <- downloadHandler(
        
        filename = function() {
            str_c("file-", Sys.Date(), ".", input$save_format)
        },
        
        content = function(file){
                # some function for saving in correct format
        }
    )
}
    
shinyApp(ui = ui, server = server)

I've also tried with disable from shinyjs right after renderUI but it didn't work. Also didnt find any updateDownloadButton function. Is there any solution for this?

Upvotes: 0

Views: 242

Answers (2)

St&#233;phane Laurent
St&#233;phane Laurent

Reputation: 84529

Certainly shinyjs::disable didn't work because the download button was not rendered yet. Here is a way which avoids renderUI, so that you can use disable. It also runs some JS code with runjs to change the label.

library(shiny)
library(shinyjs)

ui <- fluidPage(
  useShinyjs(),
  downloadButton("downloadData", "Download"),
  br(),
  selectInput(
    inputId = "save_format",
    label = NULL,
    choices = c("csv", "xlsx"),
    selected = "csv"
  )
)

server <- function(input, output) {
  # Our dataset
  data <- mtcars
  
  output$downloadData <- downloadHandler(
    filename = function() {
      paste("data-", Sys.Date(), ".csv", sep="")
    },
    content = function(file) {
      write.csv(data, file)
    }
  )
  
  disable("downloadData") # disable download button
  
  observeEvent(input$save_format, { # change download button label
    runjs(
      sprintf("$('#downloadData').contents()[2].nodeValue = '\\rDownload %s\\r'", 
              input$save_format)
    )
  })
}

shinyApp(ui, server)

Upvotes: 2

Limey
Limey

Reputation: 12461

You can be a bit sneaky and allow the downloadHandler set a reactive value and then respond to changes in the reactive value. This works for me:

library(shiny)
library(shinyjs)

ui <- navbarPage(
  useShinyjs(),
  title = "TEST",
  tabPanel(
    "EXAMPLE",
    bootstrapPage(  
      absolutePanel(
        uiOutput(outputId = "download_ui"),
        selectInput(
          inputId = "save_format",
          label = NULL,
          choices = c("format1", "format2"),
          selected = "csv"
        )
      )
    )
  )
)

server <- function(input, output) {
  v <- reactiveValues(
    downloadDone=FALSE
  )
  
  output$download_ui <- renderUI({
    downloadButton(
      outputId = "download",
      label = str_c("Download ", input$save_format)
    )
  })
  
  observeEvent(v$downloadDone, {
    if (v$downloadDone) disable("download")
    else enable("download")
  })
  
  output$download <- downloadHandler(
    filename = function() {
      str_c("file-", Sys.Date(), ".", input$save_format)
    },
    content = function(file){
      v$downloadDone <- TRUE
    }
  )
}

shinyApp(ui = ui, server = server)

Upvotes: 0

Related Questions