I have the following code to let users download data strings in csv file.
exportData = 'data:text/csv;charset=utf-8,';
exportData += 'some csv strings';
encodedUri = encodeURI(exportData);
newWindow = window.open(encodedUri);
It works just fine that if client runs the code it generates blank page and starts downloading the data in csv file.
So I tried to do this with JSON object like
exportData = 'data:text/json;charset=utf-8,';
exportData += escape(JSON.stringify(jsonObject));
encodedUri = encodeURI(exportData);
newWindow = window.open(encodedUri);
But I see only a page with the JSON data displayed on it, not downloading it.
I went through some research and this one claims to work but I don't see any difference to my code.
Am I missing something in my code?
Thanks for reading my question:)
This is how I solved it for my application:
HTML:
<a id="downloadAnchorElem" style="display:none"></a>
JS (pure JS, not jQuery here):
var dataStr = "data:text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(storageObj));
var dlAnchorElem = document.getElementById('downloadAnchorElem');
dlAnchorElem.setAttribute("href", dataStr );
dlAnchorElem.setAttribute("download", "scene.json");
dlAnchorElem.click();
In this case, storageObj is the js object you want to store, and "scene.json" is just an example name for the resulting file.
This approach has the following advantages over other proposed ones:
No HTML element needs to be clicked
Result will be named as you want it
no jQuery needed
I needed this behavior without explicit clicking since I want to trigger the download automatically at some point from js.
JS solution (no HTML required):
function downloadObjectAsJson(exportObj, exportName){
var dataStr = "data:text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(exportObj));
var downloadAnchorNode = document.createElement('a');
downloadAnchorNode.setAttribute("href", dataStr);
downloadAnchorNode.setAttribute("download", exportName + ".json");
document.body.appendChild(downloadAnchorNode); // required for firefox
downloadAnchorNode.click();
downloadAnchorNode.remove();
}
Found an answer.
var obj = {a: 123, b: "4 5 6"};
var data = "text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(obj));
$('download JSON').appendTo('#container');
seems to work fine for me.
** All credit goes to #cowboy-ben-alman, who is the author of the code above **
You could try using:
the native JavaScript API's Blob constructor and
the FileSaver.js saveAs() method
No need to deal with any HTML elements at all.
var data = {
key: 'value'
};
var fileName = 'myData.json';
// Create a blob of the data
var fileToSave = new Blob([JSON.stringify(data)], {
type: 'application/json'
});
// Save the file
saveAs(fileToSave, fileName);
If you wanted to pretty print the JSON, per this answer, you could use:
JSON.stringify(data,undefined,2)
This would be a pure JS version (adapted from cowboy's):
var obj = {a: 123, b: "4 5 6"};
var data = "text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(obj));
var a = document.createElement('a');
a.href = 'data:' + data;
a.download = 'data.json';
a.innerHTML = 'download JSON';
var container = document.getElementById('container');
container.appendChild(a);
http://jsfiddle.net/sz76c083/1
ES6+ version for 2021; no 1MB limit either:
This is adapted from #maia's version, updated for modern Javascript with the deprecated initMouseEvent replaced by new MouseEvent() and the code generally improved:
const saveTemplateAsFile = (filename, dataObjToWrite) => {
const blob = new Blob([JSON.stringify(dataObjToWrite)], { type: "text/json" });
const link = document.createElement("a");
link.download = filename;
link.href = window.URL.createObjectURL(blob);
link.dataset.downloadurl = ["text/json", link.download, link.href].join(":");
const evt = new MouseEvent("click", {
view: window,
bubbles: true,
cancelable: true,
});
link.dispatchEvent(evt);
link.remove()
};
If you want to pass an object in:
saveTemplateAsFile("filename.json", myDataObj);
Simple, clean solution for those who only target modern browsers:
function downloadTextFile(text, name) {
const a = document.createElement('a');
const type = name.split(".").pop();
a.href = URL.createObjectURL( new Blob([text], { type:`text/${type === "txt" ? "plain" : type}` }) );
a.download = name;
a.click();
}
downloadTextFile(JSON.stringify(myObj), 'myObj.json');
The following worked for me:
/* function to save JSON to file from browser
* adapted from http://bgrins.github.io/devtools-snippets/#console-save
* #param {Object} data -- json object to save
* #param {String} file -- file name to save to
*/
function saveJSON(data, filename){
if(!data) {
console.error('No data')
return;
}
if(!filename) filename = 'console.json'
if(typeof data === "object"){
data = JSON.stringify(data, undefined, 4)
}
var blob = new Blob([data], {type: 'text/json'}),
e = document.createEvent('MouseEvents'),
a = document.createElement('a')
a.download = filename
a.href = window.URL.createObjectURL(blob)
a.dataset.downloadurl = ['text/json', a.download, a.href].join(':')
e.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null)
a.dispatchEvent(e)
}
and then to call it like so
saveJSON(myJsonObject, "saved_data.json");
I recently had to create a button that would download a json file of all values of a large form. I needed this to work with IE/Edge/Chrome. This is what I did:
function download(text, name, type)
{
var file = new Blob([text], {type: type});
var isIE = /*#cc_on!#*/false || !!document.documentMode;
if (isIE)
{
window.navigator.msSaveOrOpenBlob(file, name);
}
else
{
var a = document.createElement('a');
a.href = URL.createObjectURL(file);
a.download = name;
a.click();
}
}
download(jsonData, 'Form_Data_.json','application/json');
There was one issue with filename and extension in edge but at the time of writing this seemed to be a bug with Edge that is due to be fixed.
Hope this helps someone
downloadJsonFile(data, filename: string){
// Creating a blob object from non-blob data using the Blob constructor
const blob = new Blob([JSON.stringify(data)], { type: 'application/json' });
const url = URL.createObjectURL(blob);
// Create a new anchor element
const a = document.createElement('a');
a.href = url;
a.download = filename || 'download';
a.click();
a.remove();
}
You can easily auto download file with using Blob and transfer it in first param downloadJsonFile. filename is name of file you wanna set.
The download property of links is new and not is supported in Internet Explorer (see the compatibility table here). For a cross-browser solution to this problem I would take a look at FileSaver.js
If you prefer console snippet, raser, than filename, you can do this:
window.open(URL.createObjectURL(
new Blob([JSON.stringify(JSON)], {
type: 'application/binary'}
)
))
React: add this where you want in your render method.
• Object in state:
<a
className="pull-right btn btn-primary"
style={{ margin: 10 }}
href={`data:text/json;charset=utf-8,${encodeURIComponent(
JSON.stringify(this.state.objectToDownload)
)}`}
download="data.json"
>
DOWNLOAD DATA AS JSON
</a>
• Object in props:
<a
className="pull-right btn btn-primary"
style={{ margin: 10 }}
href={`data:text/json;charset=utf-8,${encodeURIComponent(
JSON.stringify(this.props.objectToDownload)
)}`}
download="data.json"
>
DOWNLOAD DATA AS JSON
</a>
className and style are optional, modify the style according to your needs.
Try to set another MIME-type:
exportData = 'data:application/octet-stream;charset=utf-8,';
But there are can be problems with file name in save dialog.
const exportToJson = (data: {}) =>{
const link = document.createElement("a");
link.href =
data:text/json;charset=utf8,${encodeURIComponent(JSON.stringify(data))}; link.download = 'example.json'; link.click(); }
Make sure to clean up the the created link after if you don't want a random element that does nothing.
I try to create a button that would download a csv file. I have to make the file using windows-1251 charset.
But no matter what I do the file ended up in utf-8. Right now I'm trying something like:
async createCsv(result) {
const arrData = result.data
const aliases = result.aliases
let csvContent = [
Object.keys(arrData[0]).map(item => aliases[item]).join(";"),
...arrData.map(item => Object.values(item).join(";"))
]
.join("\n")
.replace(/(^\[)|(\]$)/gm, "");
const data = new Blob([csvContent], {
type: "text/csv;charset=windows-1251;"
});
const link = document.createElement("a");
link.setAttribute("href", URL.createObjectURL(data));
link.setAttribute("download", (new Date).toLocaleString() + ".csv");
link.style.visibility = 'hidden';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
And the file is in utf-8.
Is there a way to change the charset?
looking for the same last day.
that's the answer that really works
blob with conversion to 8bit cp1251 or cp1252
in my project ends up with the following
import * as iconv from 'iconv-lite'
let outdata = this.bankf.getOutputFile();
const encoded = iconv.encode (outdata,'win1251');
var file = new Blob ([encoded], {type: 'text/plain;charset=windows-1251'});
var link = document.createElement("a");
var url = URL.createObjectURL(file);
link.setAttribute("href", url);
link.setAttribute("download", "filename.txt");
document.body.appendChild(link);
link.click();
setTimeout(function() {document.body.removeChild(link); window.URL.revokeObjectURL(url); }, 0);
still looking for other solution as iconv brings around 400kb code , but for now. at least it works
I got an Api which return File, i write response into this.getPDFBuffer, here you can see it.
Main problem is that if I use my function it downloads an empty file, but if i use Postman to perform an request it saves correctly
//this.getPDFBuffer contains response.data:
var file = new Blob([this.getPDFBuffer], {type: 'application/pdf'});
var url = window.URL.createObjectURL(file);
var link = document.createElement('a');
link.setAttribute('href', url);
link.setAttribute('download','download');
link.click();
I expect download a file
This is not a full answer but:
On line 4 and line 5, I suggest using a link.href = url; instead of setAttribute(). For line 5, it is link.download = "download";. This could fix the problem, but this is not meant to be a fix, just a tip.
You also have to document.body.appendChild(link) probably after line 5 so it gets displayed in the HTML.
Also, on line 5, you might have to set different parameters(see https://www.w3schools.com/TAGS/att_a_download.asp).
Changed code:
var file = new Blob([this.getPDFBuffer], {type: 'application/pdf'});
var url = window.URL.createObjectURL(file);
var link = document.createElement('a');
link.href = url;
link.download = "download"; // Maybe 'link.download;'
document.body.appendChild(link)
link.click();
The following script creates a json file in the browser and automatically save it to disk.
It works fine with Chrome 50.0.2661.87 m but it does not work on FF 47.0a2 (although no errors are throw).
Issue seems related to (as if you comment it out works):
window.URL.revokeObjectURL(link.href);
What is the reasons for this behavior on FF? Should I omit window.URL.revokeObjectURL() at all;
Notes: It should works on the latest browsers Chrome and FireFox.
var saveDataToFile = function(data, fileName, properties) {
window.URL = window.URL || window.webkitURL;
var file = new File(data, fileName, properties),
link = document.createElement('a');
link.href = window.URL.createObjectURL(file);
link.download = fileName;
document.body.appendChild(link);
link.click();
window.URL.revokeObjectURL(link.href);// possible problem here
document.body.removeChild(link)
};
var fileName = 'test.json',
properties = {
type: 'octet/stream'
},
data = [JSON.stringify({
test: 'hello'
})];
saveDataToFile(data, fileName, properties);
Remove this line
window.URL.revokeObjectURL(link.href);
Seems like you are disposing url before it is used for download.
Test: https://jsfiddle.net/cLvf7yny/
I'am trying to download temporary result calculated by JavaScript. Say I have a string str, I want to download a file contains str and named it as data.csv, I'm using the following code:
window.open('data:text/csv;charset=utf-8,' + str);
The file can be successfully downloaded, but how can I name the file data.csv automatically rather than set the name by hand each time?
You can achieve this using the download attribute for <a> elements. For example:
Download Your Foo
This attribute indicates that the file should be downloaded (instead of displayed, if applicable) and specifies which filename should be used for the downloaded file.
Instead of using window.open() you could generate an invisible link with the download attribute and .click() it.
var str = "Name, Price\nApple, 2\nOrange, 3";
var uri = 'data:text/csv;charset=utf-8,' + str;
var downloadLink = document.createElement("a");
downloadLink.href = uri;
downloadLink.download = "data.csv";
document.body.appendChild(downloadLink);
downloadLink.click();
document.body.removeChild(downloadLink);
Unfortunately this isn't supported in all browsers, but adding it won't make things worse for other browsers: they'll continue to download the files with useless filenames. (This assumes that you're using a MIME type is that their browser attempts to download. If you're trying to let the user download an .html file instead of displaying it, this won't do you any good in unsupported browsers.)
That does not work in latest Chrome, I have modified that and the following code will work fine,
$("#download_1").on('click', function() {
var json_pre = '[{"Id":1,"UserName":"Sam Smith"},{"Id":2,"UserName":"Fred Frankly"},{"Id":1,"UserName":"Zachary Zupers"}]';
var json = $.parseJSON(json_pre);
var csv = JSON2CSV(json);
var downloadLink = document.createElement("a");
var blob = new Blob(["\ufeff", csv]);
var url = URL.createObjectURL(blob);
downloadLink.href = url;
downloadLink.download = "data.csv";
document.body.appendChild(downloadLink);
downloadLink.click();
document.body.removeChild(downloadLink);
});
So when you click on download_1 id button then it will create an invisible download link and click that. I have used another function to prepare js.
The JSON2CSV function is as follows:
function JSON2CSV(objArray) {
var array = typeof objArray != 'object' ? JSON.parse(objArray) : objArray;
var str = '';
var line = '';
for (var i = 0; i < array.length; i++) {
var line = '';
for (var index in array[i]) {
line += array[i][index] + ',';
}
line = line.slice(0, -1);
str += line + '\r\n';
}
return str;
}
Hope it will help others :)
A shorter version of accepted one (for my case had to use unicode)
var link = document.createElement("a");
link.href = 'data:text/csv,' + encodeURIComponent("algún texto");
link.download = "Example.csv";
link.click();
A solution for IE is to use msSaveBlob and pass the file name.
For modern browsers solution goes like this, tested: IE11, FF & Chrome
var csvData = new Blob([arg.data], {type: 'text/csv;charset=utf-8;'});
//IE11 & Edge
if (navigator.msSaveBlob) {
navigator.msSaveBlob(csvData, exportFilename);
} else {
//In FF link must be added to DOM to be clicked
var link = document.createElement('a');
link.href = window.URL.createObjectURL(csvData);
link.setAttribute('download', exportFilename);
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
There is a good discution about that here