Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Download octet stream via jQuery

I have implemented the following code:

I have an html button like this:

HTML

<button style="background-color: #f39900;" onclick="downCont()">
    Download all content
</button>

The downCont() function invoked on click is an ajax POST like this:

JQuery

var downCont = function() {
          $.ajax({
              method: "POST",
              contentType: "application/x-www-form-urlencoded",
              url: "<endpoint here>",
              data: {
                "tokenId": token,
                "downloadId": "cz98567354",
                "saveAs": "AllContents"
              }
            })
            .done(function() {
              alert("I have downloaded all contents!");
            });
        });

Now, the response of this POST request is used to download an archive of images which is streamed directly to the user (content-type: application/octet-stream). How can I trigger the download of the archive by the browser itself using jQuery?

like image 898
user2992527 Avatar asked Jan 23 '17 10:01

user2992527


1 Answers

You need to create a url from a data Blob, and add it to an href and trigger a click.

let url;

const saveData = (() => {
  const a = document.createElement('a');
  a.style = 'display: none';
  document.body.appendChild(a);

  return (data, fileName, type = 'octet/stream') => {
    const blob = new Blob([data], { type });

    if (navigator.msSaveBlob) {
      return navigator.msSaveBlob(blob, fileName);
    }

    if (url) {
      // Keep at most 1 blob around by removing the last used one.
      URL.revokeObjectURL(url);
    }

    url = URL.createObjectURL(blob);
    a.href = url;
    a.download = fileName;
    a.click();
    return true;
  };
})();

So this function will take your data and perform those two steps, and you can use it something like this:

$.ajax({
  method: "POST",
  contentType: "application/x-www-form-urlencoded",
  url: "<endpoint here>",
  data: {
    "tokenId": token,
    "downloadId": "cz98567354",
    "saveAs": "AllContents"
  }
})
.done((data) => saveData(data, 'myDownload.zip'));

Note that for obsolete browsers which don't support Blobs there is also an alternate way to do it with window.open using a base64 encoded data string. Also note the function I provided uses arrow functions and default args, but it's easy to ES5'ify it if you want to.

like image 192
Dominic Avatar answered Nov 05 '22 18:11

Dominic