I’m still new to Ember and application development in general and have run into a bit of a break wall. I have a table in my application that uses html/handlebars to print data from a model. I have a requirement that should allow a user to download the table into a CSV file.
I initially tried this with DatatablesJS but that broke the two-way binding between my model and the query params I am using to generate the model which I can’t allow.
I’m not sure what the best strategy is now to allow the user to export this information. I did find this add on but I have been wholly unable to get it to produce a file using the ‘Model’ method in its documentation. I get a bit lost at the end and I am unsure what to do with the
invoiceModel
.download()
.then((pdfContent) => this.saveFileAs('invoice.pdf', pdfContent, 'application/pdf'));
I have also seen suggestions that the request for a CSV file should be sent to the backend and have it return through a CSV generator but it seemed very confusing.
I can’t imagine this is a unique requirement, how do other people approach it?
I did this recently. I created a service called “download”:
import Service from '@ember/service';
export default Service.extend({
asCSV(filename, contents) {
let { document, URL } = window;
let anchor = document.createElement('a');
anchor.download = filename;
anchor.href = URL.createObjectURL(new Blob([contents], {
type: 'text/csv'
}));
document.body.appendChild(anchor);
anchor.click();
anchor.remove();
}
});
Somewhere in my app, I did this.get('download').asCSV('somefile.csv', csv);
where csv
is the data that I formatted on the client side.
3 Likes
Thats a cool idea. Still being new to Ember services are something I often forget are available to me.
In terms of the data formatting, are you able to just plant a model in there or do you create a specific dataset in the controller? Would you mind posting an example dataset?
I put a method on my report
model called toCSV()
that created a CSV string from its attributes. You could that logic in the controller too, or another service. The string should just be something like:
id,name
1,David
2,Sam
Thanks for your help! I’ve managed to create a component button that will produce and download a CSV file thanks to the above information.
I struggled with parsing an object into a CSV string but found Papa parse which is doing a bang up job.
My last hurdle is working out how to do this in a model method like you mentioned. The only way I can get it to work at the minute is by explicitly iterating on the model in the component controller which means it isn’t very flexible:
export default Component.extend({
download: service('download'),
model: null,
conData: computed('model', function() {
let newArray = [];
this.get('model').forEach(function(x) {
let newData = {
name: x.data.name,
age: x.data.age
}
newArray.push(newData)
})
return newArray
}),
actions: {
request() {
let csvArray = Papa.unparse(this.get('conData'))
this.get('download').asCSV('GeneratedReport.csv', csvArray)
}
}
});
The only thing I’vve done with models so far is to populate them from a JSON return.