How do you set the name of a blob file in JavaScript when force downloading it through window.location
?
function newFile(data) {var json = JSON.stringify(data);var blob = new Blob([json], {type: "octet/stream"});var url = window.URL.createObjectURL(blob);window.location.assign(url);}
Running the above code downloads a file instantly without a page refresh that looks like:
bfefe410-8d9c-4883-86c5-d76c50a24a1d
I want to set the filename as my-download.json instead.
Best Answer
The only way I'm aware of is the trick used by FileSaver.js:
- Create a hidden
<a>
tag. - Set its
href
attribute to the blob's URL. - Set its
download
attribute to the filename. - Click on the
<a>
tag.
Here is a simplified example (jsfiddle):
var saveData = (function () {var a = document.createElement("a");document.body.appendChild(a);a.style = "display: none";return function (data, fileName) {var json = JSON.stringify(data),blob = new Blob([json], {type: "octet/stream"}),url = window.URL.createObjectURL(blob);a.href = url;a.download = fileName;a.click();window.URL.revokeObjectURL(url);};}());var data = { x: 42, s: "hello, world", d: new Date() },fileName = "my-download.json";saveData(data, fileName);
I wrote this example just to illustrate the idea, in production code use FileSaver.js instead.
Notes
- Older browsers don't support the "download" attribute, since it's part of HTML5.
- Some file formats are considered insecure by the browser and the download fails. Saving JSON files with txt extension works for me.
I just wanted to expand on the accepted answer with support for Internet Explorer (most modern versions, anyways), and to tidy up the code using jQuery:
$(document).ready(function() {saveFile("Example.txt", "data:attachment/text", "Hello, world.");});function saveFile (name, type, data) {if (data !== null && navigator.msSaveBlob)return navigator.msSaveBlob(new Blob([data], { type: type }), name);var a = $("<a style='display: none;'/>");var url = window.URL.createObjectURL(new Blob([data], {type: type}));a.attr("href", url);a.attr("download", name);$("body").append(a);a[0].click();window.URL.revokeObjectURL(url);a.remove();}
Here is an example Fiddle. Godspeed.
Same principle as the solutions above. But I had issues with Firefox 52.0 (32 bit) where large files (>40 MBytes) are truncated at random positions. Re-scheduling the call of revokeObjectUrl() fixes this issue.
function saveFile(blob, filename) {if (window.navigator.msSaveOrOpenBlob) {window.navigator.msSaveOrOpenBlob(blob, filename);} else {const a = document.createElement('a');document.body.appendChild(a);const url = window.URL.createObjectURL(blob);a.href = url;a.download = filename;a.click();setTimeout(() => {window.URL.revokeObjectURL(url);document.body.removeChild(a);}, 0)}}
jsfiddle example
Late, but since I had the same problem I add my solution:
function newFile(data, fileName){var json = JSON.stringify(data);//IE11 supportif (window.navigator && window.navigator.msSaveOrOpenBlob) {let blob = new Blob([json], {type: "application/json"});window.navigator.msSaveOrOpenBlob(blob, fileName);} else {// other browserslet file = new File([json], fileName, {type: "application/json"});let exportUrl = URL.createObjectURL(file);window.location.assign(exportUrl);URL.revokeObjectURL(exportUrl);}}
<button onclick="newFile({a:1}, 'file.json')">Export data to JSON</button>
This is my solution. From my point of view, you can not bypass the <a>
.
function export2json() {const data = {a: '111',b: '222',c: '333'};const a = document.createElement("a");a.href = URL.createObjectURL(new Blob([JSON.stringify(data, null, 2)], {type: "application/json"}));a.setAttribute("download", "data.json");document.body.appendChild(a);a.click();document.body.removeChild(a);}
<button onclick="export2json()">Export data to json file</button>
saveFileOnUserDevice = function(file){ // content: blob, name: stringif(navigator.msSaveBlob){ // For ie and Edgereturn navigator.msSaveBlob(file.content, file.name);}else{let link = document.createElement('a');link.href = window.URL.createObjectURL(file.content);link.download = file.name;document.body.appendChild(link);link.dispatchEvent(new MouseEvent('click', {bubbles: true, cancelable: true, view: window}));link.remove();window.URL.revokeObjectURL(link.href);}}
Working example of a download button, to save a cat photo from an url as "cat.jpg":
HTML:
<button onclick="downloadUrl('https://i.imgur.com/AD3MbBi.jpg', 'cat.jpg')">Download</button>
JavaScript:
function downloadUrl(url, filename) {let xhr = new XMLHttpRequest();xhr.open("GET", url, true);xhr.responseType = "blob";xhr.onload = function(e) {if (this.status == 200) {const blob = this.response;const a = document.createElement("a");document.body.appendChild(a);const blobUrl = window.URL.createObjectURL(blob);a.href = blobUrl;a.download = filename;a.click();setTimeout(() => {window.URL.revokeObjectURL(blobUrl);document.body.removeChild(a);}, 0);}};xhr.send();}
window.location.assign did not work for me. it downloads fine but downloads without an extension for a CSV file on Windows platform. The following worked for me.
var blob = new Blob([csvString], { type: 'text/csv' });//window.location.assign(window.URL.createObjectURL(blob));var link = window.document.createElement('a');link.href = window.URL.createObjectURL(blob);// Construct filename dynamically and set to link.downloadlink.download = link.href.split('/').pop() + '.' + extension; document.body.appendChild(link);link.click();document.body.removeChild(link);
Use File instead
File support name, moreover it's created on top of Blob and can be used when you want to obtain a Blob object for a file on the user's file system.
var file = new File([json], name, {type: "octet/stream"});
this is a good easy solution for it.
function downloadBloob(blob,FileName) {var link = document.createElement("a"); // Or maybe get it from the current documentlink.href = blob;link.download = FileName;link.click();}