Shiny Starting Download From Javascript

I have a downloadHandler on my Shiny server. Is there a way to initiate the download using JavaScript? I'm asking because I'm developing my UI in Svelte. Currently, I resort to embedding a downloadLink linked to Shiny and activating it via JavaScript. This method feels inelegant, and, furthermore, it ceases to work the moment the downloadLink is made invisible, which I need.

there are different ways to visually hide things, display / visible / (probably others); which way have you been using ? try the other ways.

Hi @juka,

if your setup is svelte ui / r shiny backend - i would propose the following:

Folder structure:

app.R
www/index.html
www/js/jukaFunction.js

(Example builds strongly on https://github.com/rstudio/shiny-examples/blob/main/008-html/www/index.html)

The index.html is faking your svelte ui setup.

index.html

<html>

<head>
  <script src="shared/jquery.js" type="text/javascript"></script>
  <script src="shared/shiny.js" type="text/javascript"></script>
  <link rel="stylesheet" type="text/css" href="shared/shiny.css"/>
</head>

<body>

  <h1>HTML UI</h1>

  <p>
    <label>Distribution type:</label><br />
    <select name="dist">
      <option value="norm">Normal</option>
      <option value="unif">Uniform</option>
      <option value="lnorm">Log-normal</option>
      <option value="exp">Exponential</option>
    </select>
  </p>

  <p>
    <label>Number of observations:</label><br />
    <input type="number" name="n" value="500" min="1" max="1000" />
  </p>
  <div id="jukaDownloadLinkHolder"></div>
  <script src="./js/jukaFunction.js" type="text/javascript"></script>


  <h3>Summary of data:</h3>
  <pre id="summary" class="shiny-text-output"></pre>

  <h3>Plot of data:</h3>
  <div id="plot" class="shiny-plot-output"
       style="width: 100%; height: 300px"></div>

  <h3>Head of data:</h3>
  <div id="table" class="shiny-html-output"></div>

</body>
</html>

app.R

library(shiny)

# https://github.com/rstudio/shiny-examples/blob/main/008-html/app.R

server <- function(input, output, session) {

  session$sendCustomMessage(
    type = "sendSessionId", message = session$token
  )
  
  d <- reactive({
    dist <- switch(input$dist,
                   norm = rnorm,
                   unif = runif,
                   lnorm = rlnorm,
                   exp = rexp,
                   rnorm)
    dist(input$n)
  })
  output$plot <- renderPlot({
    dist <- input$dist
    n <- input$n
    
    hist(d(),
         main = paste("r", dist, "(", n, ")", sep = ""),
         col = "#75AADB", border = "white")
  })
  
  output$summary <- renderPrint({
    summary(d())
  })
  
  output$table <- renderTable({
    head(data.frame(x = d()))
  })
  
  output$downloadID <- downloadHandler(
    filename = function() {
      paste("data-", Sys.Date(), ".csv", sep="")
    },
    content = function(file) {
      write.csv(d(), file)
    }
  )
  
  outputOptions(output, "downloadID", suspendWhenHidden = FALSE) 
}

# Create Shiny app ----
shinyApp(ui = htmlTemplate("www/index.html"), server)

jukaFunction.js

Shiny.addCustomMessageHandler(
    type = 'sendSessionId', 
    function(message) {
      const el = document.getElementById("jukaDownloadLinkHolder");
     el.innerHTML =
          '<a id="downloadID" class="shiny-download-link shiny-bound-output" href="session/'+ message +'/download/downloadID?w=" target="_blank" download="" aria-live="polite">Download stuff</a>';
  });

So you would directly call the download link which has to be generated since the session token has to be injected into the link.

Hope it helps.

Thanks so much for this elaborate response. This solved my problem.

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.

If you have a query related to it or one of the replies, start a new topic and refer back with a link.