1
votes

I am trying to isolate a section containing a session value session$sendCustomMessage so that I can send a message when an ActionButton is clicked. The user uploads a file, then the ActionButton becomes visible. Only when the button is clicked, should we enter the isolated section of server.R. After this, some computation is done, and a file is returned to the user. However, I am failing to isolate properly, and the file is being returned even without clicking the ActionButton. Here is my App:

server.R:

library(shiny)


shinyServer(function(input, output, session) {


  observe({

    inFile <- input$upload

    if (is.null(inFile))
      return(NULL)

    # Send message indicating that the file is now uploaded
    session$sendCustomMessage("upload_ready", list(fileSize=0))

    # Read the .csv file 
    df = readLines(inFile$datapath)

    # Isolate this section from the reactive context.
    # But this is executing even if the Action Button is not
    # clicked
    isolate({

      # Make this isolated section dependent on the start_proc ActionButton
      input$start_proc

      output$data_file <- downloadHandler(
        filename = function() {
          paste('probabilities-', Sys.Date(), '.txt', sep='')
        }
        ,
        content = function(file1) {
          writeLines(df, con = file1)
        }
      )

      # I think this is the problem, the session changes even if the
      # action button is not clicked, and this is why the code is going
      # into this section.
      session$sendCustomMessage("download_ready", list(fileSize=0))

    })

  })

})

ui.R

library(shiny)
library(shinyBS)

shinyUI(fixedPage(
  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;");

    // Disable start_prob at the beginning
    $("#start_proc").hide();


    // When uploaded file is ready, give the option to start process
    Shiny.addCustomMessageHandler("upload_ready", function(message) {
    $("#start_proc").show();
    });  

    // When the start_proc button is clicked, hide the button and disable
    // 

    $("#start_proc").click(function(){
    $("#start_proc").hide();
    $("#upload").prop("disabled", true);
    });

    // Show the option to download the file when the download is ready.
    // Also hide the button stat_proc and reactivate the option to upload
    // a file.
    Shiny.addCustomMessageHandler("download_ready", function(message) {
    $("#upload").prop("disabled", false);
    $("#data_file").removeAttr("disabled").removeAttr("onclick").html(
    "<i class=\\"fa fa-download\\"></i>Download Ready");
    });
    })
    </script>
    '
  ))),
   fileInput("upload", ""),
   bsButton("start_proc", h5("Compute Probability\n"), size = "extra-small", style = "primary"),
   downloadButton("data_file"),
   helpText("Download will be available once the processing is completed.")
))
1

1 Answers

3
votes

Your problems are completely unrelated to the session variables. The only event that actually triggers the computation here is input$upload. If upload is empty your code hits following lines

if (is.null(inFile))
  return(NULL)

and everything works as expected. If file has been uploaded your program reaches isolate block. Any variable that is enclosed using isolate is not considered to be a dependency so following part of your code has no effect at all, and assumption you make in the comment is simply wrong:

isolate({
   # Make this isolated section dependent on the start_proc ActionButton
   input$start_proc
   ...
})

Even if you place input$start_proc outside the isolate block your code won't work as expected since you don't check if action button has been clicked at all.

One way to make your code work is to separate upload and download logic as follows:

shinyServer(function(input, output, session) {
    raw <- reactive({
        inFile <- input$upload
        if (is.null(inFile)) return()
        # Read the .csv file 
        readLines(inFile$datapath)
    })

    observe({
        if (is.null(raw())) return() # If input empty return
        # Send message indicating that the file is now uploaded
        session$sendCustomMessage("upload_ready", list(fileSize=0))
    })

    df <- eventReactive(
        input$start_proc, # Button clicked 
        {raw()} # Send data to download handler
    )

    observe({
        if (is.null(df())) return() # In "preprocessed" data empty return

        output$data_file <- downloadHandler(
            filename = function() {
                paste('probabilities-', Sys.Date(), '.txt', sep='')
            },
            content = function(file1) {
                writeLines(df(), con = file1)
            }
        )
        # And send meassage
        session$sendCustomMessage("download_ready", list(fileSize=0))
    })
})