'Initiate a download from google apps script

I added a new menu item to my spreadsheet using google apps script. This menu item creates a file, but I'd like for it to initiate the download of the file after creating it.

Is this possible?

Remember, this is not a web app, but a menu item in my spreadsheet.

Thanks

Edit:

Thanks to Serge insas' suggestion, the following simple script works perfectly, and opens a download window with the link I need:

function onOpen() {
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var csvMenuEntries = [ {name: "Zip all CSVs", functionName: "saveAsCSV"} ];
  ss.addMenu("CSV", csvMenuEntries);
};

function saveAsCSV() {
  var folder = createCSVs(); // creates a folder with CSV for each Sheet
  var zipFile = zipCSVs(folder, "DI.zip"); // creates a zip of all CSVs in folder

  var ui = UiApp.createApplication().setTitle("Download");
  var p = ui.createVerticalPanel();
  ui.add(p);
  p.add(ui.createAnchor("Download", zipFile.getDownloadUrl()));
  SpreadsheetApp.getActive().show(ui)
}


Solution 1:[1]

OP's answer is deprecated (in 2021), so I made a more general purpose one based on it.

Apologies it requires 2 files in the Apps Script instead of just 1 - Google be like that.


Code.gs:

// Runs when the spreadsheet starts, adds a tab at the top
function onOpen() {
  var ui = SpreadsheetApp.getUi();
  ui.createMenu('Script Menu')
    .addItem('Download a file!', 'dlFile')
    .addToUi();
}

// Run when you click "Download a file!"
function dlFile() {
  let file = DriveApp.getRootFolder().createFile('Hi.txt', 'Hello, world!');

  // Create little HTML popup with the URL of the download
  let htmlTemplate = HtmlService.createTemplateFromFile('Download.html');
  htmlTemplate.dataFromServerTemplate = { url: file.getDownloadUrl() };

  let html = htmlTemplate
    .evaluate()
    .setWidth(400)
    .setHeight(300);

  SpreadsheetApp.getUi()
    .showModalDialog(html, 'Download');
};


Download.html:

<!DOCTYPE html>
<html>
  <head>
    <script>
      let data = <?!= JSON.stringify(dataFromServerTemplate) ?>; // Stores the data directly in the javascript code

      function downloadFile() {
        document.getElementById("dlBtn").innerText = "Downloading..";

        window.open(data.url, '_blank');

        document.getElementById("dlBtn").disabled = true;
      }
    </script>
  </head>
  <body>
    <button id="dlBtn" onclick="downloadFile()">Download</button>
  </body>
</html>

Solution 2:[2]

Just adding to @dr-bracket's answer where I made some small additions to the scripts in an attempt to stop the browser from navigating away to a new tab.

I got the idea from:

Download a created Google Doc from a deployed web app (Google Apps Script)

Where @tanaike uses the google.script.run.withSuccessHandler class and method to create a popup prompt then closes and returns to your app on download. (May not popup if your browser settings are set to not pick download location.)

Code.gs:

// Runs when the spreadsheet starts, adds a tab at the top
function onOpen() {
  var ui = SpreadsheetApp.getUi();
  ui.createMenu('Script Menu')
    .addItem('Download a file!', 'dlFile')
    .addToUi();
}

// Run when you click "Download a file!"
function dlFile() {
  let file = DriveApp.getRootFolder().createFile('Hi.txt', 'Hello, world!');

  // Create little HTML popup with the URL of the download. Added filename to object. ~~~~~~~~~~~
  let htmlTemplate = HtmlService.createTemplateFromFile('Download.html');
  htmlTemplate.dataFromServerTemplate = { url: file.getDownloadUrl(), name: file.getName() };

  let html = htmlTemplate
    .evaluate()
    .setWidth(400)
    .setHeight(300);

  SpreadsheetApp.getUi()
    .showModalDialog(html, 'Download');
};

// Added the following to satisfy the withSuccessHandler method: ~~~~~~~~~~~~~
function createDownloadUrl(data) {
  return { 
    url: data.url,
    name: data.name,
  };
}

Download.html:

<!DOCTYPE html>
<html>
  <head>
    <script>
      let data = <?!= JSON.stringify(dataFromServerTemplate) ?>; // Stores the data directly in
      // the javascript code

      function downloadFile() {
        const dlBtn = document.getElementById("dlBtn");
        dlBtn.innerText = "Downloading..";

        // window.open(data.url);
        // Replaced with: 
        // the url and name variables will be returned here from the 
        // code.gs function createDownloadEvent() after it runs successfully.
        google.script.run
          .withSuccessHandler(({ url, name }) => {
              const a = document.createElement("a");
              document.body.appendChild(a);
              a.download = name;
              a.href = url;
              a.target = "_blank";
              a.click();
            })
            .createDownloadEvent(data);

        dlBtn.disabled = true;
      }
    </script>
  </head>
  <body>
    <button id="dlBtn" onclick="downloadFile()">Download</button>
  </body>
</html>

Resources:

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Drako Tech