Please find the following code for more information.
function dataToCSVTry(arr) {
var fileName = "CSVFile";
var data = "";
for (var i = 0; i < arr.length; i++) {
data += (arr[i].id + " , " + arr[i].time + "\r\n");
}
var url = 'data:text/csv;charset=utf8,' + encodeURI(data);
window.open(url, '_blank');
window.download = (url + ".txt");
var encodedUri = encodeURI(url);
var link = document.createElement("a");
link.setAttribute("href", encodedUri);
link.setAttribute("download", "my_data.csv");
link.click();
};
`
This is a function to which I'm providing JSON data as input and after that trying to convert it in to a CSV(Comma Separated Values) using a for loop.
After that i am trying to save it in both .txt and .csv format. As .txt is getting saved easily, the problem comes in excel file where the data comes like :
"1%20%2C%20161.963%0A%0D%0A2%20%2C%20473.222%0A%0D%0A3%20%2C%20error%0A%0D%0A"
where some code (from what I think) is for blank space("%20%2C%20") and some other code("%0A%0D%0A") is for newline characters. What needs to be done in order to create Excel file in the same CSV format? Is there any problem with the encodeURI part that I am using ?
Data url content isn't URI encoded, it is base-64 encoded. You should use btoa or a similar solution to create your data from the CSV string you built.
Related
I am using a nodeJS program as a server and an AngularJS web application as the client.
To create the CSV I'm using the "express-csv" library (https://www.npmjs.com/package/express-csv)
Here is my server side code:
Defines:
var app = express();
var csv = require('express-csv');
Get code:
app.get('/exportDB', function(req, res){
res.csv([
["a", "b", "c"]
, ["d", "e", "f"]
]);
Here is my client side code:
$http.get("http://"+$localStorage.ip+":"+$localStorage.port+"/exportDB").success(function(response){
// HERE I NEED A WAY TO DOWNLOAD THE RECEIVED CSV
});
Needless to say it reaches the server and everything else is working just fine, but I couldnt find a way to download the CSV. Help please.
P.S
Please don't say it's a duplicate of Prompt a csv file to download as pop up using node.js and node-csv-parser (node module) since the client side isn't really mentioned there.
Also, other questions are focused on server side instead of client.
There is no other question referring to AngularJS client.
You can just navigate:
location.href = "http://"+$localStorage.ip+":"+$localStorage.port+"/exportDB";
I faced same issue that the solutions mentioned above with works well with Chrome and Firefox, but not with safari/IE.
Tried out following hack and it worked for me-
var url="http://'+$localStorage.ip+':"+$localStorage.port+'/exportDB';
var form = angular.element("<form action='" + url +"'></form>");
form.submit();
File download will be handled by browser itself.
though following is limitation to it -
You won't be able to handle the errors (if any) from your http get call :( For this tried using try-catch block of javascript, but didn't work well...
..you wont be able to unit test this piece of code :( :(
There is another approach that worked and it was -
var url="http://'+$localStorage.ip+':"+$localStorage.port+'/exportDB';
$window.location.href = url;
Suggestions and Discussions welcome!
You can create a tag and click on it:
$http.get("http://"+$localStorage.ip+":"+$localStorage.port+"/exportDB").success(function(response) {
var dataURI = 'data:application/octet-stream;base64,' + btoa(response);
$('<a></a>').attr({
download: 'db.csv',
href: dataURI
})[0].click();
});
There are ways of downloading csv. First approach is to create a tag and click it
Add the mimeType in below code data:application/octet-stream
var a = document.createElement('a');
a.href = 'data:'+mimeType+';charset=utf-8;base64,' + response;
a.target = '_blank';
a.download = "name the file here";
document.body.appendChild(a);
a.click();
But this solution doesn't work on IE>9 and safari>6
because safari doesn't follow download attribute for anchor tag
so for safari you can use filesaver.js
and IE this solution will work
if (window.navigator.msSaveOrOpenBlob){
// base64 string
var base64str = response;
// decode base64 string, remove space for IE compatibility
var newstr =base64str.replace(/\s/g, '');
var binary = atob(newstr);
// get binary length
var len = binary.length;
// create ArrayBuffer with binary length
var buffer = new ArrayBuffer(len);
// create 8-bit Array
var view = new Uint8Array(buffer);
// save unicode of binary data into 8-bit Array
for (var i = 0; i < len; i++) {
view[i] = binary.charCodeAt(i);
}
// create the blob object with content-type "application/csv"
var blob = new Blob( [view], { type: mimeType });
window.navigator.msSaveOrOpenBlob(blob, "Name your file here");
}
Here I tried to make it simple. Assign all the back end records that you want to display in the file in the variable called obj. I will just say it as var obj = []. And inside the function just add the below code.
var a = document.createElement("a");
var csvContent = "Name, Address\n";
for(var i =0; i <obj.lenght; i++ ) {
var dataString = obj[i].name + ", " + obj[i].address + "\n";
csvContent += dataString;
}
a.href = 'data:attachment/csv;charset=utf-8,' + encodeURI(csvContent);
a.target = '_blank';
a.download = 'myFile.csv';
document.body.appendChild(a);
a.click();
I modified this code to convert JSON to .xls format. The code actually works, but while opening the file in MS Excel 2013, it throws a warning that the file format and extension do not match.
This is what I have so far:
var json3 = { "d": "[{\"Id\":1,\"UserName\":\"Sam Smith\"},{\"Id\":2,\"UserName\":\"Fred Frankly\"},{\"Id\":3,\"UserName\":\"Zachary Zupers\"}]" }
DownloadJSON2CSV(json3.d);
function DownloadJSON2CSV(objArray)
{
var array = typeof objArray != 'object' ? JSON.parse(objArray) : objArray;
var str = '';
for (var i = 0; i < array.length; i++) {
var line = '';
for (var index in array[i]) {
line += array[i][index] + '\t';
}
line.slice(0,line.Length-1);
str += line + '\r\n';
}
window.open( "data:application/vnd.ms-excel;charset=utf-8," + escape(str));
}
What am I missing?
jsFiddle
The .xls format is a far more complex (and for that matter, proprietary) file format - the modification you made only modifies the mime type, not the actual content of the file. In other words, the file is still a CSV file inside, but you just tricked your browser into thinking it's an XLS file.
More info on mime types: http://en.wikipedia.org/wiki/Internet_media_type
For a solution to your problem, if you really, REALLY need XLS, the best idea is to find an online service that offers an API which converts CSV to XLS (googling "CSV to XLS online" might help).
My web app receives data in the form of a base64 encoded string, which is decodes using atob, and stores via URL.createObjectURL(). This data is then downloaded via the right-click save-as dialog. The downloaded filed always matches the source file when the source file is ascii encoded. However this isn't the case when the source file is just plain binary data. A diff of a non ascii encoded downloaded file vs its source file appears to show that the downloaded file is UTF-8 encoded. How can this problem be fixed? Please note, I'm locked into using firefox 10.
Convert the string to a Arraybuffer and it should work. If there is any way that you can get the data into an array buffer directly without passing a sting that would be the best solution.
The following code is tested in FF10, and are using the now obsolete MozBlobBuilder.
fiddle
var str="",
idx, len,
buf, view, blobbuild, blob, url,
elem;
// create a test string
for (var idx = 0; idx < 256; ++idx) {
str += String.fromCharCode(idx);
}
// create a buffer
buf = new ArrayBuffer(str.length);
view = new Uint8Array(buf);
// convert string to buffer
for (idx = 0, len = str.length; idx < len; ++idx) {
view[idx] = str.charCodeAt(idx);
}
blobbuild = new MozBlobBuilder();
blobbuild.append(buf);
blob = blobbuild.getBlob('application/octet-stream');
url = URL.createObjectURL(blob);
elem = document.createElement('a');
elem.href = url;
elem.textContent = 'Test';
document.body.appendChild(elem);
I am trying to save a generated zip-file to disk from within a chrome extension with the follwing code:
function sendFile (nm, file) {
var a = document.createElement('a');
a.href = window.URL.createObjectURL(file);
a.download = nm; // file name
a.style.display = 'none';
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
}
function downloadZip (nm) {
window.URL = window.webkitURL || window.URL;
var content;
content = zip.generate();
var file = new Blob ([content], {type:'application/base64'});
sendFile ("x.b64", file);
content = zip.generate({base64:false});
var file = new Blob ([content], {type:'application/binary'});
sendFile ("x.zip", file);
}
Currently this saves the contents of my zip in two versions, the first one is base64 encoded, and when I decode it with base64 -d the resulting zip is ok.
The second version should just save the raw data (the zip file), but this raw data arrives utf-8 encoded on my disk. (each value >= 0x80 is preprended with 0xc2). So how to get rid of this utf-8 encoding? Tried various type-strings like application/zip, or ommitting the type info completely, it just arrives always with utf-8 encoding. I am also curious how to make the browser store/convert base64-data (the first case) by itself, so that they arrive as decoded binary data on my disk... I'm using Chrome Version 23.0.1271.95 m
PS: The second content I analysed with a hexdump-utility inside the browser: it does not contain utf-8 encodings (or my hexdump calls something which does implicit conversion). For completeness (sorry, its just transposed from c, so it might not be that cool js-code), I append it here:
function hex (bytes, val) {
var ret="";
var tmp="";
for (var i=0;i<bytes;i++) {
tmp=val.toString (16);
if (tmp.length<2)
tmp="0"+tmp;
ret=tmp+ret;
val>>=8;
}
return ret;
}
function hexdump (buf, len) {
var p=0;
while (p<len) {
line=hex (2,p);
var i;
for (i=0;i<16;i++) {
if (i==8)
line +=" ";
if (p+i<len)
line+=" "+hex(1,buf.charCodeAt(p+i));
else
line+=" ";
}
line+=" |";
for (i=0;i<16;i++) {
if (p+i<len) {
var cc=buf.charCodeAt (p+i);
line+= ((cc>=32)&&(cc<=127)&&(cc!='|')?String.fromCharCode(cc):'.');
}
}
p+=16;
console.log (line);
}
}
From working draft:
If element is a DOMString, run the following substeps:
Let s be the result of converting element to a sequence of Unicode characters [Unicode] using the algorithm for doing so in WebIDL
[WebIDL].
Encode s as UTF-8 and append the resulting bytes to bytes.
So strings are always converted to UTF-8, and there is no parameter to affect this. This doesn't affect base64 strings because they only contain characters that match single byte per codepoint, with the codepoint and byte having the same value. Luckily Blob exposes lower level interface (direct bytes), so that limitation doesn't really matter.
You could do this:
var binaryString = zip.generate({base64: false}), //By glancing over the source I trust the string is in "binary" form
len = binaryString.length, //I.E. having only code points 0 - 255 that represent bytes
bytes = new Uint8Array(len);
for( var i = 0; i < len; ++i ) {
bytes[i] = binaryString.charCodeAt(i);
}
var file = new Blob([bytes], {type:'application/zip'});
sendFile( "myzip.zip", file );
I am trying to export some data in csv format, it is fetched from my database (mongodb) with AJAX calls.
The problem is that special characters (e.g é à) are not displayed correctly in Excel after the CSV import.
However, they are correctly displayed on LibreOffice/Open Office, Google Spreadsheetm, and any text editor I could try.
I assume that the file is encoded in UTF-16 since it's generated from javascript.
Here's how I created the export in JavaScript (this is AngularJS) :
$scope.downloadCityCSV = function() {
$scope.csvURL = 'building';
var data = 'email;first name;last name;Email confirmé;city;quantity;date\n';
$scope.campaignData.cityVotes.forEach(function(vote) {
var customer = vote.customer;
data += customer.email +';' + customer.firstName +';' + customer.lastName +';' + (customer.accountConfirmed?"O":"N") +';' + vote.cityProposal + ';' + vote.quantity + ';' + vote.created + '\n';
});
var blob = new Blob([data], { type : 'text/csv' });
$scope.csvURL = (window.URL || window.webkitURL).createObjectURL(blob);
};
Did I do something wrong?