Javascript: Exporting large text/csv file crashes Google Chrome - javascript

I have the following Javascript code to export CSV file on the client side. However Google Chrome crashes every time I try to export a large array. What is the limit of the data string allowed in Chrome? Is it possible that it is hitting the memory limit allowed in Chrome? If the data string is too long for Chrome, how will I go about exporting large CSV files on the client side?
var csvRows = [...]; //Array with 40000 items, each item is 100 characters long.
var csvString = csvRows.join("\r\n");
var a = document.createElement('a');
a.href = 'data:text/csv;charset=utf-8,' + encodeURIComponent(csvString);
a.target = '_blank';
a.download = 'export.csv';
document.body.appendChild(a);
a.click();
(Expected file size is about 6.4MB)

had the same Problem and solved it using Blob.
For example:
csvData = new Blob([csvString], { type: 'text/csv' });
var csvUrl = URL.createObjectURL(csvData);
a.href = csvUrl;
Source:
https://stackoverflow.com/a/24611096/3048937

I used following function to download CSV. Worked for me in IE/Firefox/Chrome
function downloadFile(data, fileName) {
var csvData = data;
var blob = new Blob([ csvData ], {
type : "application/csv;charset=utf-8;"
});
if (window.navigator.msSaveBlob) {
// FOR IE BROWSER
navigator.msSaveBlob(blob, fileName);
} else {
// FOR OTHER BROWSERS
var link = document.createElement("a");
var csvUrl = URL.createObjectURL(blob);
link.href = csvUrl;
link.style = "visibility:hidden";
link.download = fileName;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
}

Related

JS download doesn't download entire file

I am trying to download a csv file with 3607 lines (1.0 Mb):
const hiddenElement = document.createElement('a');
const fileContent = `data:text/csv;charset=ansi,${res.data}`;
hiddenElement.href = fileContent;
hiddenElement.target = '_blank';
hiddenElement.download = 'file.csv';
hiddenElement.click();
The content at res.data is complete (as well as fileContent), but when i download the csv, the file only has 149 lines (4.4 Kb) instead of the original size.
Can someone help me please?
The problem was that URLs cant have more than 2,048 characters
I faced the same problem and the same CSV download used to work earlier and download complete file.
had to change to the following:
const blob = new Blob([csvData], { type: 'text/csv' })
const url = window.URL.createObjectURL(blob);
const link = document.createElement('a')
link.setAttribute('href', url)

Downloading a webform JSON object list in Firefox 26

I'm forced to use an old firefox version 26. I have the below code working perfectly on firefox 72, way more recent, I know. While stepping through the download function, I realize my problem has something to do with the a.click(). While comparing the debugging consoles between browsers I don't notice any differences in the function, but the a.click() isn't triggering the saveAs popup.
Here is the json list format, which has indices equal to n select box elements.
testn:{
val: "pass",
desc: "test description"}
JS
jsonData = $("#myform").serializeArray();
function download(content, fileName, contentType) {
var a = document.createElement("a");
var file = new Blob([content], {type: contentType});
a.href = URL.createObjectURL(file);
a.download = fileName;
a.click();
}
if (confirm("Save results to <SCRIPT_PATH_LOCATION>")){
download(JSON.stringify(jsonData), 'webform.results.json', 'text/plain');
} else {
return false
}
I figured it out. Modern convenience allowed me to get away with not adequately appending the new element, "a" onto the webform.
JS
jsonData = $("#myform").serializeArray();
function download(content, fileName, contentType) {
var a = document.createElement("a");
//Insert these
document.body.appendChild(a);
a.style = "display: none";
//Insert complete
var file = new Blob([content], {type: contentType});
a.href = URL.createObjectURL(file);
a.download = fileName;
a.click();
}
if (confirm("Save results to <SCRIPT_PATH_LOCATION>")){
download(JSON.stringify(jsonData), 'webform.results.json', 'text/plain');
} else {
return false
}

how to get mime type from content-type

The thing is axios calls return files. sometimes xlsx, sometimes plain txt.
In javascript, as soon as I get them, i force download it via blob.
Something like this:
var headers = response.headers;
var blob = new Blob([response.data], {
type: headers['content-type']
});
var link = document.createElement('a');
link.href = window.URL.createObjectURL(blob);
link.download = "report.xlsx";
link.click();
As you see, I got something like this: link.download = "report.xlsx" . What I want is to replace xlsx with dynamic mime type so that sometimes it's report.txt and sometimes it's report.xlsx.
How do I do that from content-type?
You can get the file extension using the content type of headers.
Use this Javascript library - node-mime
You just want to pass your headers['content-type'], it will give you the file extension which you need to set for download name.
var ctype = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
console.log(mime.getExtension(ctype));
<script src="https://wzrd.in/standalone/mime#latest"></script>
Example: In your case,
var headers = response.headers;
var blob = new Blob([response.data], {
type: headers['content-type']
});
var link = document.createElement('a');
link.href = window.URL.createObjectURL(blob);
link.download = "report." + mime.getExtension(headers['content-type']);
link.click();
Incomplete list of MIME types from Mozilla Developers.
What is the backend of your application? I used this in C# (.NET Core) to get the content type of a file then set it as a header in the response:
public string GetContentType (string filePath) {
var contentTypeProvider = new FileExtensionContentTypeProvider();
string contentType;
if( !contentTypeProvider.TryGetContentType( filePath, out contentType ) ) {
contentType = "application/octet-stream";
};
return contentType;
}
Edit: modified OP code to handle content type dynamically:
var headers = response.headers;
var responseType = headers['content-type'];
var fileType = "text/plain";
var fileName = "report.txt";
if ( responseType == "application/octet-stream" ) {
fileType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
fileName = "report.xlsx";
}
var blob = new Blob([response.data], {
type: fileType
});
var link = document.createElement('a');
link.href = window.URL.createObjectURL(blob);
link.download = fileName;
link.click();

Angular 13 - Download file from ByteArray data

I get a byte[] file from my server with the content of a file. I know the name and the content-type. So far I have tried the following for downloading the file:
const a = document.createElement('a');
document.body.appendChild(a);
a.style.display = 'none';
const file = new Blob([content], {type: 'text/plain'});
const url = window.URL.createObjectURL(file);
a.href = url;
a.download = "test.txt";
a.click();
window.URL.revokeObjectURL(url);
But this solution just downloads a text file with the binary content in it. How can I convert the binary data to the correspondent file type in the client side using JavaScript/Typescript? Thanks!
You can use file-saver
import { saveAs } from 'file-saver';
const file = new Blob([content], {type: 'text/plain'});
FileSaver.saveAs(file, "test.txt");
saveByteArray(bytes, type) {
var blob = new Blob([bytes],{type:type});
var link = document.createElement('a');
link.href = window.URL.createObjectURL(blob);
link.download = "fileName";
link.click();
}

Download File from Bytes in JavaScript

I want to download the file which is coming in the form of bytes from the AJAX response.
I tried to do it this way with the help of Blob:
var blob=new Blob([resultByte], {type: "application/pdf"});
var link=document.createElement('a');
link.href=window.URL.createObjectURL(blob);
link.download="myFileName.pdf";
link.click();
It is in fact downloading the pdf file but the file itself is corrupted.
How can I accomplish this?
I asked the question long time ago, so I might be wrong in some details.
It turns out that Blob needs array buffers. That's why base64 bytes need to be converted to array buffers first.
Here is the function to do that:
function base64ToArrayBuffer(base64) {
var binaryString = window.atob(base64);
var binaryLen = binaryString.length;
var bytes = new Uint8Array(binaryLen);
for (var i = 0; i < binaryLen; i++) {
var ascii = binaryString.charCodeAt(i);
bytes[i] = ascii;
}
return bytes;
}
Here is my function to save a pdf file:
function saveByteArray(reportName, byte) {
var blob = new Blob([byte], {type: "application/pdf"});
var link = document.createElement('a');
link.href = window.URL.createObjectURL(blob);
var fileName = reportName;
link.download = fileName;
link.click();
};
Here is how to use these two functions together:
var sampleArr = base64ToArrayBuffer(data);
saveByteArray("Sample Report", sampleArr);
You just need to add one extra line and it should work. Your response is byte array from your server application
var bytes = new Uint8Array(resultByte); // pass your byte response to this constructor
var blob=new Blob([bytes], {type: "application/pdf"});// change resultByte to bytes
var link=document.createElement('a');
link.href=window.URL.createObjectURL(blob);
link.download="myFileName.pdf";
link.click();
Set Blob type at Blob constructor instead of at createObjectURL
var blob = new Blob([resultByte], {type: "application/pdf"});
var link = document.createElement("a");
link.href = window.URL.createObjectURL(blob);
link.download = "myFileName.pdf";
link.click();
Easiest way would be converting bytes to the base64 format and construct link as below
let link=document.createElement('a');
const mimeType = "application/pdf";
link.href=`data:${mimeType};base64,${base64Str}`;
link.download="myFileName.pdf";
link.click();
Link can be generated on backend side and retrieved from the response.
File bytes can be read as base64 string in Python as following:
with open("my-file.pdf", "rb") as file:
base46_str = base64.b64encode(file.read()).decode("utf-8")

Categories