Filename of downloaded file in data:Application/octet-stream; - html

I am trying to download a file using data uri in following manner:
<input type="button"
onclick="window.location.href='data:Application/octet-stream;content-disposition:attachment;filename=file.txt,${details}'"
value="Download"/>
The problem is that the downloaded file is always named 'Unknown', whatever I try to use as
filename. Is this the correct way to give the file a name ? or something else needs to be
done ?

Here's the solution, you just have to add a download attribute to anchor tag
a with desired name
<a href="data:application/csv;charset=utf-8,Col1%2CCol2%2CCol3%0AVal1%2CVal2%2CVal3%0AVal11%2CVal22%2CVal33%0AVal111%2CVal222%2CVal333"
download="somedata.csv">Example</a>
Another solution is to use JQuery/Javascript
Anchor's Download Property

On Safari, you might want to use this, and instruct the user to ⌘-S the file:
window.open('data:text/csv;base64,' + encodeURI($window.btoa(content)));
Otherwise, this uses Filesaver.js, but works ok:
var downloadFile = function downloadFile(content, filename) {
var supportsDownloadAttribute = 'download' in document.createElement('a');
if(supportsDownloadAttribute) {
var link = angular.element('<a/>');
link.attr({
href: 'data:attachment/csv;base64,' + encodeURI($window.btoa(content)),
target: '_blank',
download: filename
})[0].click();
$timeout(function() {
link.remove();
}, 50);
} else if(typeof safari !== 'undefined') {
window.open('data:attachment/csv;charset=utf-8,' + encodeURI(content));
} else {
var blob = new Blob([content], {type: "text/plain;charset=utf-8"});
saveAs(blob, filename);
}
}
Note: There is some AngularJS in the code above, but it should be easy to factor out...

I had the same issue and finally I solved in all browsers serving the CSV file in the server-side:
const result = json2csv({ data });
res.writeHead(200
'Content-Type': 'application/octet-stream',
'Content-Disposition': 'attachment;filename=issues.csv',
'Content-Length': result.length
});
res.end(result);

For those that are using other libraries like angularjs or backbone, you can try something like this.
$('a.download').attr('href', 'data:application/csv;charset=utf-8,'+$scope.data);

For anybody looking for a client-side solution using Javascript only, here is mine, working on any browser except IE 10 and lower (and Edge...why?!):
var uri = 'data:application/csv;charset=UTF-8,' + encodeURIComponent(csv);
var link = document.createElement('a');
link.setAttribute("download", "extract.csv");
link.setAttribute("href", uri);
document.body.appendChild(link);
link.click();
body.removeChild(body.lastChild);

Related

Display a pdf file in the browser with sails

I have some documents in a directory and I want to show one embedded in the browser, I save the path of the document in a table and I can read the path from that table and download the document, but I can't figure out how to show the file in the browser.
I'm using the following code to send the file:
loadDocument: async function (req,res){
var SkipperDisk = require('skipper-disk');
var fileAdapter = SkipperDisk(/* optional opts */);
var fd = await Documents.find(
{
where: {id:'1'},
select: ['uploadFileFd']
}
).limit(1);
let uploadFileFd = fd[0]["uploadFileFd"];
var fileStream = fileAdapter.read(uploadFileFd);
fileStream.on('error', function (err){
return res.serverError(err);
});
res.contentType("application/pdf");
res.set("Content-disposition", "attachment; filename=" + "file"+ fd[0]["id"]+".pdf");
fileStream.pipe(res);
},
I want to call the function and load the pdf file in the browser, preferably without reloading all the page.
Clients browsers will download the pdf without trying to open the built-in PDF viewer (ie, Chrome) because of the Content-disposition: attachment header that you're sending - try using inline instead.
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition
res.setHeader('Content-type', 'application/pdf');
res.setHeader('Content-disposition', 'inline; filename="file' + fd[0]["id"] + '.pdf"');
I found a solution to my problem.
First I have to create a way to serve the static folder where the files are located, I found the answer here.
Then I modify the code to send the data encoded as base64 using 'base64-stream':
var readStream = fs.createReadStream(uploadFileFd);
readStream.on('open', function () {
readStream.pipe(new Base64Encode()).pipe(res);
});
readStream.on('error', function(err) {
res.end(err);
});
Finally I show the pdf file in the browser as follows:
.done(function(data){
var parent = $('embed#pdf').parent();
var newElement = "<embed src=data:application/pdf;base64,"+data+" id='pdf' width='100%' height='1200'>";
$('embed#pdf').remove();
parent.append(newElement);
})
Now I can display a pdf file in the browser embedded in my own page, thanks to all the people that try to help.

Force <a download /> to download image instead of opening url link to image [duplicate]

This question already has answers here:
How can I create download link in HTML?
(12 answers)
Closed 1 year ago.
<a download='file' href="https://tinyjpg.com/images/social/website.jpg">
Download
</a>
Is there a way to force the download of a file instead of opening the file in a new window? Right now if the file is a URL, like the example below it won't be downloaded and will open in a new window.
You may be bitten by the fact that Firefox and Chrome 65+ only support same-origin download links, probably as a security measure.
Source: https://caniuse.com/#feat=download (see "Known issues" tab)
The Web Hypertext Application Technology Working Group (WHATWG) recommends that in cross-origin scenarios (as in your example), the web server that is hosting the image/file in question needs to send a Content-Disposition HTTP header for download= to be honored.
Source: https://html.spec.whatwg.org/multipage/links.html#downloading-resources
In short:
You can only use <a download='...'></a> to force download of an image/file, if:
the html and the image/file are hosted on the same domain,or
the image/file is on a different domain, and that server also says it should be downloaded.
Maybe you have solved in the meanwhile, but since you are hosting the files on S3 (see comments on Peter B's answer), you need to add a signature to the files url and set the ResponseContentType to binary/octet-stream by using the aws sdk. I am using Node so it becomes:
const promises = array.map((item) => {
const promise = s3.getSignedUrlPromise('getObject', {
Bucket: process.env.S3_BUCKET,
Key: key, //filename
Expires: 604800, //time to expire in seconds (optional)
ResponseContentType: 'binary/octet-stream'
});
return promise;
});
const links = await Promise.all(promises);
I hope this helps.
setTimeout(function() {
url = 'https://media.sproutsocial.com/uploads/2017/02/10x-featured-social-media-image-size.png';
// downloadFile(url); // UNCOMMENT THIS LINE TO MAKE IT WORK
}, 2000);
// Source: http://pixelscommander.com/en/javascript/javascript-file-download-ignore-content-type/
window.downloadFile = function (sUrl) {
//iOS devices do not support downloading. We have to inform user about this.
if (/(iP)/g.test(navigator.userAgent)) {
//alert('Your device does not support files downloading. Please try again in desktop browser.');
window.open(sUrl, '_blank');
return false;
}
//If in Chrome or Safari - download via virtual link click
if (window.downloadFile.isChrome || window.downloadFile.isSafari) {
//Creating new link node.
var link = document.createElement('a');
link.href = sUrl;
link.setAttribute('target','_blank');
if (link.download !== undefined) {
//Set HTML5 download attribute. This will prevent file from opening if supported.
var fileName = sUrl.substring(sUrl.lastIndexOf('/') + 1, sUrl.length);
link.download = fileName;
}
//Dispatching click event.
if (document.createEvent) {
var e = document.createEvent('MouseEvents');
e.initEvent('click', true, true);
link.dispatchEvent(e);
return true;
}
}
// Force file download (whether supported by server).
if (sUrl.indexOf('?') === -1) {
sUrl += '?download';
}
window.open(sUrl, '_blank');
return true;
}
window.downloadFile.isChrome = navigator.userAgent.toLowerCase().indexOf('chrome') > -1;
window.downloadFile.isSafari = navigator.userAgent.toLowerCase().indexOf('safari') > -1;
You can use this function to downlaod images using fetch
async function downloadImage(imageSrc) {
const image = await fetch(imageSrc)
const imageBlog = await image.blob()
const imageURL = URL.createObjectURL(imageBlog)
const link = document.createElement('a')
link.href = imageURL
link.download = 'image file name here'
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
}
Your link should have an ID to force download:
<a download='website.jpg' id='blablabla' href="https://tinyjpg.com/images/social/website.jpg">
Download
</a>

HTML <a> tag download file error handling

In my app I have tag with link to api for file download (pdf). The problem is that it is not 100% stable and I have to handle then service is not available or file is not available and server responds with error.
<a href="link/to/api" target="_blank" download="filename">
By the way I am using AngularJS in this app. If there is any solution using it it would help a lot
In case somebody else will face similar problem. Here is the solution I have implemented after some research.
Remove the link from an <a> tag and add a click event:
<a href="#" ng-click="downloadFile()">
now you need to download blob (here you can control if you can access it file) and let make DOM object add all needed attributes end trigger it.
$scope.downloadFile = function () {
$http.get('api/link', { responseType: 'arraybuffer' })
.then(function (data) {
var file = new Blob([data], { type: "application/pdf" });
var url = $window.URL || $window.webkitURL;
var fileURL = url.createObjectURL(file);
var a = document.createElement("a");
a.href = fileURL;
a.download = "nameOfFile";
a.target = "_self";
a.click();
url.revokeObjectURL(fileURL);
}).error(function (data) {
console.error(data);
})
};
UPDATE:
This was working only for Chrome. Other browsers had different approach of downloading blob. So I have users FileSaver.js for this task. Even then I had problems opening it on iOS. It is blocking file saving if it was triggered out side of user event. Here is my workaround for this.
var file = new Blob([data], { type: "application/pdf" });
var isIos = (navigator.userAgent.match(/(iPad|iPhone|iPod)/g) ? true : false);
if(isIos){
var element = document.getElementById("downloadButton");
element.onclick - function(){
saveAs(file, "name.pdf");
}
element.onclick();
} else {
saveAs(file, "name.pdf");
}
Hope this will save time for someone.
Use extensionnames after the link like link/to/api.pdf and download="filename.pdf".
Also, try target="_self"

IE 9+ Download Attribute workaround

I am trying to download a file from my web service. I need to pass complex meta data to the server to know how to download the file. Here is how Im able to accomplish that in evergreen browsers:
// i use angular but not important for this demo
$http.post({ /* complex object */ }).then(xhr){
// use download attribute
// http://davidwalsh.name/download-attribute
var hiddenElement = document.createElement('a');
hiddenElement.href = 'data:attachment/csv,' + encodeURI(xhr.data);
hiddenElement.target = '_blank';
hiddenElement.download = $scope.filename + '.csv';
hiddenElement.click();
hiddenElement.remove();
});
of course sense the download attribute is not available on IE I'm not able to post. A workaround I've used before is:
$("body>#download_iFrame").remove();
$("body").append('<iframe name="downloadFrame" id="download_iFrame" style="display:none;" src="" />');
$("#form-download")[0].submit();
and then in html
<form target="downloadFrame"
action="'api/search/export/'"
id="form-download"></form>
problem is I can't pass a object like that. Sure I can put a hidden input and serialize its value but my object is kinda big so that ends up being a problem.
How do you work around this?
If you're only concerned about recent browsers you might take a look at using FileSaver.js. When running on IE10+ it uses navigator.msSaveOrOpenBlob.
var xhr = new XMLHttpRequest();
xhr.open("GET", url, true);
xhr.responseType = "blob";
xhr.onload = fuction (eventInfo) {
if (this.status == 200) {
var blob = this.response;
// FileSaver.js usage:
saveAs(blob, "filename.ext");
// Or IE10+ specific:
navigator.msSaveOrOpenBlob(blob, "filename.ext");
}
};
xhr.send();

Download attribute on A tag not working in IE

From the following code I'm creating a dynamic anchor tag which downloads a file. This code works well in Chrome but not in IE. How can I get this working
<div id="divContainer">
<h3>Sample title</h3>
</div>
<button onclick="clicker()">Click me</button>
<script type="text/javascript">
function clicker() {
var anchorTag = document.createElement('a');
anchorTag.href = "http://cdn1.dailymirror.lk/media/images/finance.jpg";
anchorTag.download = "download";
anchorTag.click();
var element = document.getElementById('divContainer');
element.appendChild(anchorTag);
}
</script>
Internet Explorer does not presently support the Download attribute on A tags.
See http://caniuse.com/download and http://status.modern.ie/adownloadattribute; the latter indicates that the feature is "Under consideration" for IE12.
In my case, since there's a requirement to support the usage of IE 11 (version 11.0.9600.18665), I ended up using the solution provided by #Henners on his comment:
// IE10+ : (has Blob, but not a[download] or URL)
if (navigator.msSaveBlob) {
return navigator.msSaveBlob(blob, fileName);
}
It's quite simple and practical.
Apparently, this solution was found on the Javascript download function created by dandavis.
Old question, but thought I'd add our solution. Here is the code I used on my last project. It's not perfect, but it passed QA in all browsers and IE9+.
downloadCSV(data,fileName){
var blob = new Blob([data], {type: "text/plain;charset=utf-8;"});
var anchor = angular.element('<a/>');
if (window.navigator.msSaveBlob) { // IE
window.navigator.msSaveOrOpenBlob(blob, fileName)
} else if (navigator.userAgent.search("Firefox") !== -1) { // Firefox
anchor.css({display: 'none'});
angular.element(document.body).append(anchor);
anchor.attr({
href: 'data:attachment/csv;charset=utf-8,' + encodeURIComponent(data),
target: '_blank',
download: fileName
})[0].click();
anchor.remove();
} else { // Chrome
anchor.attr({
href: URL.createObjectURL(blob),
target: '_blank',
download: fileName
})[0].click();
}
}
Using the ms specific API worked best for us in IE. Also note that some browsers require the anchor to actually be in the DOM for the download attribute to work, whereas Chrome, for example, does not. Also, we found some inconsistencies with how Blobs work in various browsers. Some browsers also have an export limit. This allows the largest possible CSV export in each browser afaik.
As of build 10547+, the Microsoft Edge browser is now supporting the download attribute on a tags.
Download Image
Edge features update: https://dev.windows.com/en-us/microsoft-edge/platform/changelog/desktop/10547/
a[download] standard: http://www.w3.org/html/wg/drafts/html/master/links.html#attr-hyperlink-download
This code fragment allows saving blob in the file in IE, Edge and other modern browsers.
var request = new XMLHttpRequest();
request.onreadystatechange = function() {
if (request.readyState === 4 && request.status === 200) {
// Extract filename form response using regex
var filename = "";
var disposition = request.getResponseHeader('Content-Disposition');
if (disposition && disposition.indexOf('attachment') !== -1) {
var filenameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/;
var matches = filenameRegex.exec(disposition);
if (matches != null && matches[1]) filename = matches[1].replace(/['"]/g, '');
}
if (window.navigator.msSaveOrOpenBlob) { // for IE and Edge
window.navigator.msSaveBlob(request.response, filename);
} else {
// for modern browsers
var a = document.createElement('a');
a.href = window.URL.createObjectURL(request.response);
a.download = filename;
a.style.display = 'none';
document.body.appendChild(a);
a.click();
}
}
button.disabled = false;
dragArea.removeAttribute('spinner-visible');
// spinner.style.display = "none";
};
request.open("POST", "download");
request.responseType = 'blob';
request.send(formData);
For IE and Edge use: msSaveBlob
Use my function
It bind your atag to download file in IE
function MS_bindDownload(el) {
if(el === undefined){
throw Error('I need element parameter.');
}
if(el.href === ''){
throw Error('The element has no href value.');
}
var filename = el.getAttribute('download');
if (filename === null || filename === ''){
var tmp = el.href.split('/');
filename = tmp[tmp.length-1];
}
el.addEventListener('click', function (evt) {
evt.preventDefault();
var xhr = new XMLHttpRequest();
xhr.onloadstart = function () {
xhr.responseType = 'blob';
};
xhr.onload = function () {
navigator.msSaveOrOpenBlob(xhr.response, filename);
};
xhr.open("GET", el.href, true);
xhr.send();
})
}
Append child first and then click
Or you can use window.location= 'url' ;
As mentioned in earlier answer , download attribute is not supported in IE . As a work around, you can use iFrames to download the file . Here is a sample code snippet.
function downloadFile(url){
var oIframe = window.document.createElement('iframe');
var $body = jQuery(document.body);
var $oIframe = jQuery(oIframe).attr({
src: url,
style: 'display:none'
});
$body.append($oIframe);
}
I copied the code from here and updated it for ES6 and ESLint and added it to my project.
You can save the code to download.js and use it in your project like this:
import Download from './download'
Download('/somefile.png', 'somefile.png')
Note that it supports dataURLs (from canvas objects), and more... see https://github.com/rndme for details.