4

I've written a NodeJS/Express application that generates and downloads an excel document (created using ExcelJS) upon the user pressing a button. When the user presses the button, the file is generated then downloaded to the user's default download location. I'd prefer the user be able to select where they'd like to download the file upon pressing the button. Is this possible?

My current JavaScript code is as follows:

export_button.onclick = async function() {
    await fetch('/download', {
        method: 'POST'
    })
    .then(resp => resp.blob())
    .then(blob => {
        const url = window.URL.createObjectURL(blob);
        const a = document.createElement('a');
        a.style.display = 'none';
        a.href = url;
        a.download = 'document.xlsx';
        document.body.appendChild(a);
        a.click();
        window.URL.revokeObjectURL(url);
    });
}
GriffsAccount
  • 95
  • 1
  • 12

3 Answers3

4

This is possible in desktop versions of latest Chrome-based browsers (Chrome, Edge, Opera).

Current support: https://caniuse.com/mdn-api_window_showsavefilepicker

https://wicg.github.io/file-system-access/#api-showsavefilepicker
https://wicg.github.io/file-system-access/#enumdef-wellknowndirectory


We use this for working with PDF files: https://webpdf.pro/doc/ (draft for next release).
Note that you can suggest a file name and folder, customize the file type list, offer multiple types! showSaveFilePicker In fact, we have a method called exactly that: <pdf-file>.saveAs().

draft


Online version of Visual Studio Code is another recent user: https://vscode.dev/.


Apple and Firefox are likely to drag their feet on this one citing privacy/security concerns for at least the next few months though.

Cetin Sert
  • 4,497
  • 5
  • 38
  • 76
  • 2
    Just added to my code and it seems to work great! Perhaps I'm being picky, but I noticed when the file downloads successfully, the prompt showing the file has completed downloading doesn't pop up. Anything you've found so it does pop up? – GriffsAccount Oct 28 '21 at 21:28
  • 1
    @GriffsAccount – The **showSaveFilePicker()** API just gives us a handle to a file, we can use **and re-use** for writing to the file. Because we can re-write to a file to which we still maintain the handle, I believe browser vendors are opting to stay away rather than pop sth. up on each re-write. In a way, the API is designed rather for long term multi-read/write scenarios in the first place. Any progress / completion would have to be indicated by you. Please look at how https://vscode.dev behaves for that. – Cetin Sert Oct 28 '21 at 21:36
0

I don't believe this is possible, no. This behaviour is controlled by settings in the user's browser. For most browsers, or perhaps even all of them, the default behaviour is to always download files to a default location without showing a prompt where the user can change its destination or filename. Understandably, you can't change a user's browser settings from JavaScript.

Glad to see I was wrong about this, I didn't realise the File System Access API Cetin Sert's answer describes exists.

Mark Hanna
  • 3,206
  • 1
  • 17
  • 25
0

async function saveFile(){
      var mystring = "Hello World!";
      var myblob = new Blob([mystring], {
        type: 'text/plain'
      });

      if( window.showSaveFilePicker ) {
            const opts = {
                types: [{
                  description: 'MYfile',
                  accept: {'text/plain': ['.txt']},
                }],
                suggestedName: 'myFileText',
              };
            var handle = await showSaveFilePicker(opts);
            var writable = await handle.createWritable();
            await writable.write( myblob );
            writable.close();
        }else{
          alert( "xxx" );
        }
}
<button id="botonx" onClick="saveFile()" >Save File</button>
Muisca
  • 69
  • 1
  • 5