I am building an app using node.js that needs to allow the user to download a .csv file.
The problem - the app does not send a file to the client as an attachment when the user clicks a button. HOWEVER, if the client goes directly to the API link, the file will download. E.g. - if the user goes to localhost:3000/api/exportmetric
, the a file will be sent to the client as an attachment. But if that route is hit as an AJAX request, nothing happens.
User flow:
1) User clicks a button
2) App makes AJAX GET request to server
3) Server retrieves data from a database
4) Server parses the data into a .csv file
5) Server sends file back to the client to download as an attachment.
My code:
client.js
$("#export_velocity").click(function(e) {
console.log('export to velocity hit');
$.ajax({
url: 'http://localhost:3001/api/exportmetric',
type: 'GET',
success: function(response) {
console.log(response);
},
error: function(a, b, c) {
console.log(a);
console.log(b);
console.log(c);
}
});
});
server.js
router.get('/api/exportmetric', function(req, res) {
console.log('export metric hit');
var fields = ['first_name', 'last_name', 'age'];
var fieldNames = ['First Name', 'Last Name', 'Age??'];
var people = [
{
"first_name": "George",
"last_name": "Lopez",
"age": "31"
}, {
"first_name": "John",
"last_name": "Doe",
"age": "15"
}, {
"first_name": "Jenna",
"last_name": "Grassley",
"age": "44"
}
];
json2csv({ data: people, fields: fields, fieldNames: fieldNames }, function(err, csv) {
res.setHeader('Content-disposition', 'attachment; filename=file.csv');
res.set('Content-Type', 'text/csv');
console.log(csv)
res.status(200).send(csv);
});
});
There are basically two popular ways to download a file.
1. Set window.location
Setting window.location
to the download url will download the file.
window.location = '/path/to/download?arg=1';
A slightly different version of this is to open a new tab with the download path
window.open('/path/to/download', '_self');
2. Virtual Link Click
With HTML5, you can specify the download
attribute of a link. Clicking the link (even programmatically) will trigger a download of the url. The links don't even need to be part of the DOM, you can make them dynamically.
var link = document.createElement('a');
link.href = '/path/to/download';
link.download = 'local_filename.csv';
var e = document.createEvent('MouseEvents');
e.initEvent('click', true, true);
link.dispatchEvent(e);
This isn't supported in all browsers, so even if you want to use this method, you'll have to drop support for some browsers or fallback to the first method.
Luckily, this excellent answer references an awesome little js
library that does all this already -- http://pixelscommander.com/polygon/downloadjs/#.VrGw3vkrKHv
downloadFile('/path/to/download');
2-Step Download
Another convention you'll often see is a two step download, where information is sent to the server at a known url, and the server sends back a generated url or id that can be used to download the file.
This can be useful if you want the url to be something that can be shared, or if you have to pass a lot of parameters to the download generator or just want to do it via a POST
request.
$.ajax({
type: 'POST',
url: '/download/path/generator',
data: {'arg': 1, 'params': 'foo'},
success: function(data, textStatus, request) {
var download_id = data['id'];
// Could also use the link-click method.
window.location = '/path/to/download?id=' + download_id;
}
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With