Downloading a webform JSON object list in Firefox 26 - javascript

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
}

Related

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();
}

octet stream download as csv doesn't work in IE [duplicate]

I have this in my Angular.js controller that downloads a CSV file:
var blob = new Blob([csvContent.join('')], { type: 'text/csv;charset=utf-8'});
var link = document.createElementNS('http://www.w3.org/1999/xhtml', 'a');
link.href = URL.createObjectURL(blob);
link.download = 'teams.csv';
link.click();
This works perfectly in Chrome but not in IE. A browser console log says:
HTML7007: One or more blob URLs were revoked by closing the blob for
which they were created. These URLs will no longer resolve as the data
backing the URL has been freed.
What does it mean and how can I fix it?
Try this using, this or useragent
if (navigator.appVersion.toString().indexOf('.NET') > 0)
window.navigator.msSaveBlob(blob, filename);
else
{
var blob = new Blob(['stringhere'], { type: 'text/csv;charset=utf-8' });
var link = document.createElementNS('http://www.w3.org/1999/xhtml', 'a');
link.href = URL.createObjectURL(blob);
link.download = 'teams.csv';
link.click();
}
IE won't allow you to open blobs directly. You have to use msSaveOrOpenBlob. There's also msSaveBlob
if (window.navigator && window.navigator.msSaveOrOpenBlob) {
window.navigator.msSaveOrOpenBlob(blob, fileName);
} else {
var objectUrl = URL.createObjectURL(blob);
window.open(objectUrl);
}
I needed to use a Blob to download a converted a base64 PNG image. I was able to successfully download the blob on IE11 with window.navigator.msSaveBlob
See the following msdn link:
http://msdn.microsoft.com/en-us/library/hh779016(v=vs.85).aspx
Specifically, you should call:
window.navigator.msSaveBlob(blobObject, 'msSaveBlob_testFile.txt');
where blobObject is a Blob created in the usual fashion.
Complete Solution for Chrome, Internet Explorer Firefox and Opera
There are lots of nice bits on this page, but I had to use a combination of a few things to get it all to work. Hopefully this helps you.
Use a button or link to trigger a function called download():
<button class="button-no save-btn" ng-click="download()">DOWNLOAD</button>
Put this in your controller:
$scope.download = function () {
// example shows a JSON file
var content = JSON.stringify($scope.stuffToPutInFile, null, " ");
var blob = new Blob([content], {type: 'application/json;charset=utf-8'});
if (window.navigator && window.navigator.msSaveBlob) {
// Internet Explorer workaround
$log.warn("Triggering download using msSaveBlob");
window.navigator.msSaveBlob(blob, "export.json");
} else {
// other browsers
$log.warn("Triggering download using webkit");
var url = (window.URL || window.webkitURL).createObjectURL(blob);
// create invisible element
var downloadLink = angular.element('<a></a>');
downloadLink.attr('href', url);
downloadLink.attr('download', 'export.json');
// make link invisible and add to the DOM (Firefox)
downloadLink.attr('style','display:none');
angular.element(document.body).append(downloadLink);
// trigger click
downloadLink[0].click();
}
};
What's your IE browser version? You need a modern browser or IE10+
http://caniuse.com/bloburls
Maybe you need some delay. What about with:
link.click();
setTimeout(function(){
document.body.createElementNS('http://www.w3.org/1999/xhtml', 'a');
URL.revokeObjectURL(link.href);
}, 100);
I needed to get the download feature to work in Chrome and IE11. I had good success with this code.
HTML
<div ng-repeat="attachment in attachments">
<a ng-click="openAttachment(attachment)" ng-href="{{attachment.fileRef}}">{{attachment.filename}}</a>
</div>
JS
$scope.openAttachment = function (attachment) {
if (window.navigator && window.navigator.msSaveOrOpenBlob) {
window.navigator.msSaveOrOpenBlob(
b64toBlob(attachment.attachment, attachment.mimeType),
attachment.filename
);
}
};
Done it this way, working fine for me.
downloadFile(data) {
if (navigator.msSaveBlob) {
let blob = new Blob([data], {
"type": "text/csv;charset=utf8;"
});
navigator.msSaveBlob(blob, this.fileName);
}
else {
let blob = new Blob(['\ufeff' + data], { type: 'text/csv;charset=utf-8;' });
let $link = document.createElement("a");
let url = URL.createObjectURL(blob);
$link.setAttribute("target", "_blank");
$link.setAttribute("href", url);
$link.setAttribute("download", this.fileName);
$link.style.visibility = "hidden";
document.body.appendChild($link);
$link.click();
document.body.removeChild($link);
}
}
Try to use this instead :
var blob = file.slice(0, file.size);
Create polyfill method as below,had a variable filename since in my case download filename was static.This method will be called while blob function is not supported as in case of Internet explorer
if (!HTMLCanvasElement.prototype.toBlob) {
Object.defineProperty(HTMLCanvasElement.prototype,
'toBlob', {
value: function (callback, type, quality) {
var canvas = this;
setTimeout(function () {
var binStr = atob(canvas.toDataURL(type, quality).split(',')[1]),
len = binStr.length,
arr = new Uint8Array(len);
for (var i = 0; i < len; i++) {
arr[i] = binStr.charCodeAt(i);
}
var blob = new Blob([arr], {
type: 'image/png'
});
window.navigator.msSaveOrOpenBlob(blob, fileName);
});
}
});
}
try {
const blob = new Blob([res.body], {
type: res.headers.get('Content-Type'),
});
const file = new File([blob], this.getFileName(res), {
type: res.headers.get('Content-Type'),
});
saveAs(file);
} catch (err) {
var textFileAsBlob = new Blob([res.body], {
type: res.headers.get('Content-Type'),
});
window.navigator.msSaveBlob(textFileAsBlob, this.getFileName(res));
}
To get the file name. Use the below function.
getFileName(response: any) {
let name: string;
try {
const contentDisposition: string = response.headers.get(
'content-disposition'
);
const [, filename] = contentDisposition.split('filename=');
name = filename;
} catch (e) {
name = 'File_Name_Not_Specified_' + new Date();
}
return name;
}
This worked for me.

Javascript: Exporting large text/csv file crashes Google Chrome

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);
}
}

Save json string to client pc (using HTML5 API)

I read few older thread about the same, but seen the file API changed a lot recently. My requirement is to save a json file (data is locally in indexdDB, but I need a way to back it up). Since I use indexdDB, I only target recent browsers, mainly chrome. So, it it possible to save data (json string) to client computer?
I have seen http://eligrey.com/demos/FileSaver.js/ , but is there a way to do it natively?
Thanks.
You can use a Blob and the HTML5 a[download] feature to provide a JSON backup download:
var data = {a:1, b:2, c:3};
var json = JSON.stringify(data);
var blob = new Blob([json], {type: "application/json"});
var url = URL.createObjectURL(blob);
var a = document.createElement('a');
a.download = "backup.json";
a.href = url;
a.textContent = "Download backup.json";
Here is a jsfiddle example: http://jsfiddle.net/potatosalad/yuM2N/
Yes, you can. This assumes that you have the json in text:
var toDownload=new Blob([text],{type:'x-whatever/x-backup'});
var link=window.URL.createObjectURL(toDownload);
window.location=link;
that is untested, but it should work.
You can use FileSaver.js.
Sample code:
//include the js file in html.
<script src="FileSaver.min.js"></script>
// other code ...
//use it here.
var myjson= "{a:3, b:4}";
var blob = new Blob([myjson], {type: "application/json"});
var saveAs = window.saveAs;
saveAs(blob, "my_outfile.json");
Use JSON.stringify to create a string from JSON.
Fiddle: https://jsfiddle.net/9w9ofec4/3/
based on potatosalad answer i experimented with an 'self' updating link:
jsfiddle
function saveAsFile(link, content, filename) {
var blob = new Blob([content], {type: "text/text"});
var url = URL.createObjectURL(blob);
// update link to new 'url'
link.download = filename + ".txt";
link.href = url;
}
saveAsFile(this, "YourContent", "HelloWorldFile");
the function saveAsFile() needs the calling a element as first argument.
than it updates the href target to the new blob.
function saveAsJSON(data, name=Date.now()+'.json') {
const a = document.createElement('a')
a.download = name
a.href = URL.createObjectURL(new Blob([JSON.stringify(data)], {type: 'application/json'}))
a.click()
}
// https://stackoverflow.com/questions/62371219/chrome-stops-download-files-from-stackoverflow-snippets
saveAsJSON(['orange', 'banana', {name: 'apple'}])
To save the file with a custom name, you can create a hidden <a> element and then click on it. This method is used by FileSaver.js.
function download(name, text){
var toDownload=new Blob([text],
{type:'data:application/octet-stream'});
var link = window.URL.createObjectURL(toDownload);
var el = document.createElement("a");
el.href = link;
el.download = name;
el.click();
window.URL.revokeObjectURL(link);
}

Categories