Shiny App:Disable Downloadbutton

shiny app : disable downloadbutton

Based on your comment:

yes data processing depends on the user input. USer will upload some files and click anAction button to start the processing. The download button is in a tab set.

Let's say the action button is named input$start_proc.

In server.R:

shinyServer(function(input, output, session) {
#... other code
observe({
if (input$start_proc > 0) {
# crunch data...
# when data is ready:
session$sendCustomMessage("download_ready", list(...))
# you can put extra information you want to send to the client
# in the ... part.
}
})
#... other code
})

Then in ui.R, you can write some javascript to handler the custom message event.


A full example is:

server.R

library(shiny)

fakeDataProcessing <- function(duration) {
# does nothing but sleep for "duration" seconds while
# pretending some background task is going on...
Sys.sleep(duration)
}

shinyServer(function(input, output, session) {

observe({
if (input$start_proc > 0) {
fakeDataProcessing(5)
# notify the browser that the data is ready to download
session$sendCustomMessage("download_ready", list(fileSize=floor(runif(1) * 10000)))
}
})

output$data_file <- downloadHandler(
filename = function() {
paste('data-', Sys.Date(), '.csv', sep='')
},
content = function(file) {
write.csv(data.frame(x=runif(5), y=rnorm(5)), file)
}
)
})

ui.R

library(shiny)

shinyUI(fluidPage(
singleton(tags$head(HTML(
'
<script type="text/javascript">
$(document).ready(function() {
// disable download at startup. data_file is the id of the downloadButton
$("#data_file").attr("disabled", "true").attr("onclick", "return false;");

Shiny.addCustomMessageHandler("download_ready", function(message) {
$("#data_file").removeAttr("disabled").removeAttr("onclick").html(
"<i class=\\"fa fa-download\\"></i>Download (file size: " + message.fileSize + ")");
});
})
</script>
'
))),
tabsetPanel(
tabPanel('Data download example',
actionButton("start_proc", h5("Click to start processing data")),
hr(),

downloadButton("data_file"),
helpText("Download will be available once the processing is completed.")
)
)
))

In the example the data processing is faked by waiting for 5 seconds.
Then the download button will be ready. I also added some "fake" fileSize information in the message to demonstrate that how you can send extra information to the user.

Note that because Shiny implements actionButton as <a> tag instead of <button>, and it binds click event on it. Therefore, in order to fully disable it, in addition to add a disabled attribute to make it appear to be disabled, you also need to override its click event by adding an inline onclick attribute. Otherwise the user can still accidentally click the (seemingly disabled) download button and triggers the download.

disable downloadButton when no shiny checkboxGroupInput item selected

In your observe, you need to know to disable it as well. You can use an else clause with disable, or you can just use

  observe({
shinyjs::toggleState("download_bttn", condition = !is.null(input$iris_species))
})

in place of your current observe block.

Disable downloadButton after renderUI

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)

Display download button in Shiny R only when output appears in Main Panel

On server side you can use:

output$download <- renderUI({
if(!is.null(input$file1) & !is.null(input$file2)) {
downloadButton('OutputFile', 'Download Output File')
}
})

and on ui side you replace the download button with:

uiOutput("download")

Shinydashboard grayed out downloadButton?

It looks like ANY download button you place inside the sidebar looks like that (nothing to do with the fact it was using hide/show). If you simply move the button to the body instead of the sidebar, it looks normal again, and if you add more buttons to the sidebar they all are grayed out as well. So this tells us that it's probably something about the CSS.

If you look at the CSS of the button, you'll see the rule

.skin-blue .sidebar a {
color: #b8c7ce;
}

So it looks like someone (either shiny or bootstrap, I'm not sure who is responsible for this CSS file) it purposely making links (and a download button is really just a link that's styled differently) gray text. So you can fix this by adding your own CSS like

tags$style(".skin-blue .sidebar a { color: #444; }")

Is there a way to prevent the download page from opening in R Shiny?

Vincent's solution using two buttons, an action button for the calculation and a download button for the download is the one I went with. An additional bonus to this solution is the progress bar that also comes in the shinyIncubator package.

An explanation of my code incase someone else wants to do the same thing:

The ui.R has an action button and a dynamic download button:

actionButton("makePlots", "Calculate Results"),
uiOutput("download_button")

and a progress initialisation for the progress bar:

  mainPanel(
progressInit(),
uiOutput("mytabs")) # dynamic rendering of the tabs

The server.R is a little more complex. So that the download button is only shown when there is something to download I used the dynamic uiOutput with the following code:

    output$download_button <- renderUI({
if(download){
downloadButton("downloadPlots", "Download Results")
}
})

The download button is only shown when download==TRUE. At the start of server.R the variable is initialised: download<-FALSE

As the action button increases by 1 everytime it is clicked I included a counter (initial value 0) that increases after each "use" of the action button. Reason for this is the first if statement.

makePlots<-reactive({

if(input$makePlots>counter){ # tests whether action button has been clicked

dir.create("new_directory_for_output")

withProgress(session, min=1, max=15, expr={ # setup progress bar

for(i in 1:15){

png(paste0("new_directory_for_output/plot",i,".png"))
plot(i)
dev.off()

setProgress(message = 'Calculation in progress',
detail = 'This may take a while...',
value=i)

} # end for

}) # end progress bar

counter<<-counter+1 # needs the <<- otherwise the value of counter
# is only changed within the function

download<<-TRUE # something to download

} # end if

}) # end function

At this stage the function makePlots() doesn't have an output and isn't called anywhere so it does nothing. I therefore placed makePlots() at the beginning of each tab so that no matter which tab the user is on, once the action button has been clicked the plots are made and saved.

The final piece of teh puzzle is the download handler:

output$downloadPlots <- downloadHandler(

filename = function() { my_filename.zip },
content = function(file){

fname <- paste(file,"zip",sep=".")
zip(fname,new_directory_for_output) # zip all files in the directory
file.rename(fname,file)

unlink(new_directory_for_output,recursive = TRUE) # delete temp directory
download<<-FALSE # hide download button
}

) # end download handler


Related Topics



Leave a reply



Submit