Export javascript data to CSV file without server interaction - javascript

If we were on a nodeJS server, we could write a header, set a mime type, and send it:
res.header("Content-Disposition", "attachment;filename="+name+".csv");
res.type("text/csv");
res.send(200, csvString);
and because of the headers, the browser will create a download for the named csv file.
When useful data is generated in a browser, one solution to getting it in a CSV file is to use ajax, upload it to the server, (perhaps optionally save it there) and get the server to send it back with these headers to become a csv download back at the browser.
However, I would like a 100% browser solution that does not involve ping-pong with the server.
So it occurred to me that one could open a new window and try to set the header with a META tag equivalent.
But this doesn't work for me in recent Chrome.
I do get a new window, and it contains the csvString, but does not act as a download.
I guess I expected to get either a download in a bottom tab or a blank new window with a download in a bottom tab.
I'm wondering if the meta tags are correct or if other tags are also needed.
Is there a way to make this work without punting it to the server?
JsFiddle for Creating a CSV in the Browser (not working - outputs window but no download)
var A = [['n','sqrt(n)']]; // initialize array of rows with header row as 1st item
for(var j=1;j<10;++j){ A.push([j, Math.sqrt(j)]) }
var csvRows = [];
for(var i=0,l=A.length; i<l; ++i){
csvRows.push(A[i].join(',')); // unquoted CSV row
}
var csvString = csvRows.join("\n");
console.log(csvString);
var csvWin = window.open("","","");
csvWin.document.write('<meta name="content-type" content="text/csv">');
csvWin.document.write('<meta name="content-disposition" content="attachment; filename=data.csv"> ');
csvWin.document.write(csvString);

There's always the HTML5 download attribute :
This attribute, if present, indicates that the author intends the
hyperlink to be used for downloading a resource so that when the user
clicks on the link they will be prompted to save it as a local file.
If the attribute has a value, the value will be used as the pre-filled
file name in the Save prompt that opens when the user clicks on the
link.
var A = [['n','sqrt(n)']];
for(var j=1; j<10; ++j){
A.push([j, Math.sqrt(j)]);
}
var csvRows = [];
for(var i=0, l=A.length; i<l; ++i){
csvRows.push(A[i].join(','));
}
var csvString = csvRows.join("%0A");
var a = document.createElement('a');
a.href = 'data:attachment/csv,' + encodeURIComponent(csvString);
a.target = '_blank';
a.download = 'myFile.csv';
document.body.appendChild(a);
a.click();
FIDDLE
Tested in Chrome and Firefox, works fine in the newest versions (as of July 2013).
Works in Opera as well, but does not set the filename (as of July 2013).
Does not seem to work in IE9 (big suprise) (as of July 2013).
An overview over what browsers support the download attribute can be found Here
For non-supporting browsers, one has to set the appropriate headers on the serverside.
Apparently there is a hack for IE10 and IE11, which doesn't support the download attribute (Edge does however).
var A = [['n','sqrt(n)']];
for(var j=1; j<10; ++j){
A.push([j, Math.sqrt(j)]);
}
var csvRows = [];
for(var i=0, l=A.length; i<l; ++i){
csvRows.push(A[i].join(','));
}
var csvString = csvRows.join("%0A");
if (window.navigator.msSaveOrOpenBlob) {
var blob = new Blob([csvString]);
window.navigator.msSaveOrOpenBlob(blob, 'myFile.csv');
} else {
var a = document.createElement('a');
a.href = 'data:attachment/csv,' + encodeURIComponent(csvString);
a.target = '_blank';
a.download = 'myFile.csv';
document.body.appendChild(a);
a.click();
}

#adeneo answer works for Firefox and chrome... For IE the below can be used.
if (window.navigator.msSaveOrOpenBlob) {
var blob = new Blob([decodeURIComponent(encodeURI(result.data))], {
type: "text/csv;charset=utf-8;"
});
navigator.msSaveBlob(blob, 'FileName.csv');
}

See adeneo's answer, but don't forget encodeURIComponent!
a.href = 'data:application/csv;charset=utf-8,' + encodeURIComponent(csvString);
Also, I needed to do "\r\n" not just "\n" for the row delimiter.
var csvString = csvRows.join("\r\n");
Revised fiddle: http://jsfiddle.net/7Q3c6/

Once I packed JS code doing that to a tiny library:
https://github.com/AlexLibs/client-side-csv-generator
The Code, Documentation and Demo/Playground are provided on Github.
Enjoy :)
Pull requests are welcome.

We can easily create and export/download the excel file with any separator (in this answer I am using the comma separator) using javascript. I am not using any external package for creating the excel file.
var Head = [[
'Heading 1',
'Heading 2',
'Heading 3',
'Heading 4'
]];
var row = [
{key1:1,key2:2, key3:3, key4:4},
{key1:2,key2:5, key3:6, key4:7},
{key1:3,key2:2, key3:3, key4:4},
{key1:4,key2:2, key3:3, key4:4},
{key1:5,key2:2, key3:3, key4:4}
];
for (var item = 0; item < row.length; ++item) {
Head.push([
row[item].key1,
row[item].key2,
row[item].key3,
row[item].key4
]);
}
var csvRows = [];
for (var cell = 0; cell < Head.length; ++cell) {
csvRows.push(Head[cell].join(','));
}
var csvString = csvRows.join("\n");
let csvFile = new Blob([csvString], { type: "text/csv" });
let downloadLink = document.createElement("a");
downloadLink.download = 'MYCSVFILE.csv';
downloadLink.href = window.URL.createObjectURL(csvFile);
downloadLink.style.display = "none";
document.body.appendChild(downloadLink);
downloadLink.click();

See adeneo's answer, but to make this work in Excel in all countries you should add "SEP=," to the first line of the file. This will set the standard separator in Excel and will not show up in the actual document
var csvString = "SEP=, \n" + csvRows.join("\r\n");

Related

Export javascript loop to CSV

Suppose I have this loop code.
for (var i = 0; i < originList.length; i++) {
var results = response.rows[i].elements;
for (var j = 0; j < results.length; j++) {
outputDiv.innerHTML += results[j].distance.text + ',';
}
}
I want to export the outputDiv.innerHTML into CSV with this code, but it doesn't work.
function downloadFile(fileName, urlData) {
var aLink = document.createElement('a');
aLink.download = fileName;
aLink.href = urlData;
var event = new MouseEvent('click');
aLink.dispatchEvent(event);
}
downloadFile('output.csv', 'outputDiv.innerHTML/csv;charset=UTF-8,' + encodeURIComponent(outputDiv.innerHTML));
What should I do? I'm new at this. Thank you.
This solution is in JavaScript. I added an event listener to the button so when it is clicked, it will grab the outerHTML of <table>.
outerHTML essentially includes the opening and closing tags of the element as well as the content whereas innerHTML does not include the opening and closing tags.
From MDN Web Docs
The outerHTML attribute of the Element DOM interface gets the serialized HTML fragment describing the element including its descendants. It can also be set to replace the element with nodes parsed from the given string.
When the innerText is extracted from the all rows and columns. download_csv is called.
You can download the data using a Blob object which is a file-like object of immutable, raw data.
document.querySelector("button").addEventListener("click", function () {
let html = document.querySelector("table").outerHTML;
exportToCSV(html, "table.csv");
});
function exportToCSV(html, filename) {
let csv = [];
// grab all rows inside table
let rows = document.querySelectorAll("table tr");
let row, cols;
for (let i = 0; i < rows.length; i++) {
row = []; // will hold innerText of all columns
// retrieve all columns of row
cols = rows[i].querySelectorAll("td, th");
for (let j = 0; j < cols.length; j++){
// push column innerText
row.push(cols[j].innerText);
}
// push all innerText into CSV
csv.push(row.join(","));
}
console.log("Extracted content from html:",csv);
// Download CSV
download_csv(csv.join("\n"), filename);
}
function download_csv(csv, filename) {
let csvFile;
let downloadLink;
// CSV FILE
csvFile = new Blob([csv], {type: "text/csv"});
// create an element and set the file name.
downloadLink = document.createElement("a");
downloadLink.download = filename;
// We have to create a link to the file
downloadLink.href = window.URL.createObjectURL(csvFile);
// prevent link from being shown
downloadLink.style.display = "none";
// Add the link to your DOM
document.body.appendChild(downloadLink);
// start the download
downloadLink.click();
}
<table>
<tr><th>Name</th><th>Age</th><th>Country</th></tr>
<tr><td>Tony</td><td>26</td><td>USA</td></tr>
<tr><td>Levi</td><td>19</td><td>Spain</td></tr>
<tr><td>Calvin</td><td>32</td><td>Russia</td></tr>
</table>
<button>Export HTML table to CSV file</button>
I do not know what are you trying to achieve in your last line, but that does not look like a dataURL, a dataURL looks like:
data:[][;base64],
Now that being said, the idea is to create an object url through a combination of Blob and window.URL.createObjectURL:
function dL(input,fileName){
var blob = new Blob(input,{type:"text/csv"}),
url = window.URL.createObjectURL(blob),
aElem = document.createElement("a"),
fileName = "deogenResults.txt";
aElem.setAttribute("href",url);
aElem.setAttribute("download",fileName);
if (window.navigator.constructor.prototype.hasOwnProperty("msSaveBlob")) {
window.navigator.msSaveBlob(blob,fileName);
} else if ("download" in aElem) {
aElem.click();
} else {
window.open(url,"_blank");
}
setTimeout(function(){window.URL.revokeObjectURL(url)},2000);
}
Use it like this: dL(outputDiv.innerHTML,"someName")
It is important to remind you that some browsers might not allow click to trigger on an element that is NOT in the DOM yet, in that case you might want to append the a element to the body, set it invisible and then remove it inside setTimeout.
I wrote it in plain ES5, you can adapt with const,Promise instead of setTimeout etc declarations accordingly.
A good answer here by dandavis:
It uses a library by http://danml.com/js/download.js you make sure your div contents contains comma seperated content.
var csv = jQuery(".list").map(function(a, i) {
return $.trim($(this).text()).split(/\s*\n\s*/).join(",");
}).toArray().join("\r\n");
alert(csv); // Contents
// Download
// download(csv, "tabledata.csv", "text/csv");
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="http://danml.com/js/download.js"></script> <!-- CSV -->
<div class="list">
1, 2, 3
</div>

How to add Comment in CSV Header using JavaScript/JQuery

I want to add a comment on Header fields of CSV File generated by Javascript
Also, I have Searched out for these requirements but can't find any solutions
Here is code that's using for generating CSV File using Javascript
var data = [
['123'],
['346'],
['789'],
['Test1'],
['Test2']
];
function download_csv() {
var csv = 'ID\n';
data.forEach(function(row) {
csv += row.join(',');
csv += "\n";
});
console.log(csv);
var hiddenElement = document.createElement('a');
hiddenElement.href = 'data:text/csv;charset=utf-8,' + encodeURI(csv);
hiddenElement.target = '_blank';
hiddenElement.download = 'test.csv';
document.getElementById('container').appendChild(hiddenElement);
hiddenElement.click();
}
<button onclick="download_csv()">Download CSV</button>
<div id="container" style="display:none;"></div>
I want to Add Header Comment like Here
There is no standard way to achieve this using CSV. However, you can resort to writing the file as XLXS as commenting is an application specific feature.

Downloading file made with jquery's .innerhtml breaks at the first "#"

I have this code:
function download()
{
var a = document.body.appendChild(document.createElement("a"));
a.download = "CalExport.svg";
var dd = document.getElementById('SvgResult');
alert(dd.innerHTML); //displays fine
a.href = "data:image/svg+xml," + dd.innerHTML;
a.click();//downloaded file cuts off at the first "#"
}
When the alert displays it it's okay, the downloaded version is cut off before the first "#". How do I fix this?
Since this is part of a href, you need to url-encode your data first, eg.
function download()
{
var a = document.body.appendChild(document.createElement("a"));
a.download = "CalExport.svg";
var dd = document.getElementById('SvgResult');
alert(dd.innerHTML); //should still display fine
a.href = "data:image/svg+xml," + encodeURIComponent(dd.innerHTML);
a.click();//should now not cut off.
}
The safe variation of # in a url is %23%0A (check out this tool: http://meyerweb.com/eric/tools/dencoder/).

Adding junk character in currency symbol while exporting data to CSV

I am getting strange Issue that whenever I am exporting the data in csv which have a currency symbol, It has added junk extra character in the data beside the currency symbol.
For example if My data = France - Admin Fee 1 x £100
I am getting the result like = France - Admin Fee 1 x £100 when i open this in Excel. My code is :
<html>
<head>
<script type="text/javascript">
function CreateCSV()
{
var buffer = "France - Admin Fee 1 x £100";
buffer = "\"" + buffer + "\"";
// buffer = "" + euro; //"\u2034";
var uri = "data:text/csv;charset=UTF," + encodeURIComponent(buffer);
var fileName = "InvoiceData.csv";
var link = document.createElement("a");
if (link.download !== undefined) { // feature detection
// Browsers that support HTML5 download attribute
link.setAttribute("href", uri);
link.setAttribute("download", fileName);
}
else if (navigator.msSaveBlob) { // IE 10+
link.addEventListener("click", function (event) {
var blob = new Blob([buffer], {
"type": "data:text/csv;charset=UTF;"
});
navigator.msSaveBlob(blob, fileName);
}, false);
}
else {
// it needs to implement server side export
}
link.innerHTML = "Export to CSV";
link.click();
}
</script>
</head>
<body>
<input type="button" value="Download CSV" onclick="CreateCSV()" />
</body>
</html>
When i open the same in notepad. I cannot see the junk character. I am very thankful if you can get me a work around.
The character set should probably be UTF-8. Also check the unicode for the £, I do believe it is u2034. You can find a chart here, and it lists it as U+00A3. If you have something more advanced than just Notepad, like Notepad++ for example, check the encoding type when you open the time. Excel can be finicky.

create a downloadable csv from a json string

Target: write&download a csv file starting with a json string, for example data.csv containing
col1,col2,col3
"324","19-08-2014","13000"
"325","19-08-2014","5010"
What I have done until now:
1) iframe and button to call my conversion function
<iframe id="frame" style="display:none"></iframe>
<form><input type="submit" value="Export CSV" onclick="javascript:Download();"></form>
2) my Download() function which would want to download my csv file
<script type="text/javascript">
function Download(){
var csv=ConvertToCSV(<?php echo $json_string ?>);
var url='data:application/csv,'+csv;
var _iframe_dl = $('<iframe />')
.attr('src', url)
.hide()
.appendTo('body');
};
</script>
3) my json to csv conversion function which tries to create a csv string
<script type="text/javascript">
function ConvertToCSV(json) {
var array = typeof json != 'object' ? JSON.parse(json) : json;
var str = '';
for (var i = 0; i < array.length; i++) {
var line = '';
for (var index in array[i]) {
if (line != '') line += ','
line += '"'+array[i][index]+'"';
}
str += line + "\r\n";
}
return str;
}
</script>
Encountered problems :
i) it seems that it doesn't recognize \r\n, infact output is just one line
"324","19-08-2014","13000""325","19-08-2014","5010"
ii) I cannot set the filename and the extension, infact the downloaded file is "download" without extension containing the single line mentioned above
First of all, you will need to ensure your data is in this format, like the example below.
var array = [["col1","col2","col3"],["324","19-08-2014","13000"],["324","19-08-2014","13000"]]
then you need to create csv variable as shown below
var csv = "data:text/csv;charset=utf-8,";
after this you need to loop through your data array and append each line to the csv variable you just set.
array.forEach(function(arrayItem, index){
arrayAsString = arrayItem.join(",");
csv += index < array.length ? arrayAsString+ "\n" : arrayAsString;
});
now to give this file a name and create a download link you must create a hidden anchor node and set its download attribute.
var encUri = encodeURI(csv);
var link = document.createElement("a");
link.setAttribute("href", encUri);
link.setAttribute("download", "file_name.csv");
//add anchor element to body
document.body.appendChild(link);
link.click();
EDIT:
Tested on Chrome and is working, also on Safari. Does not work on Firefox for some reason which i will take a look at now
I found out that if you add the link into the body of the page only then will Firefox initiate the download, you can use a code like so. I have updated my code above
document.body.appendChild(link);

Categories