Skip to content

Instantly share code, notes, and snippets.

@derekshi
Last active July 2, 2020 10:54
Show Gist options
  • Save derekshi/2d4969c59627ab5aca65b37eaeab72fc to your computer and use it in GitHub Desktop.
Save derekshi/2d4969c59627ab5aca65b37eaeab72fc to your computer and use it in GitHub Desktop.
ng2-csv-downloader (Angular2 CSV Downloader): Simple Angular 2 Component for downloading any data as csv.
import {Component, Input, Output, EventEmitter, Renderer} from '@angular/core';
@Component({
selector: 'csv-downloader',
template: `
<button class='btn btn-info' (click)="build()">{{downloaderName}}</button>
`
})
export class CsvDownloader {
@Input() downloaderName: string = 'Download CSV';
@Input() headers: string[] = [];
@Input() data: any[] = [];
@Input() fileName: string = 'data.csv';
@Output() onError = new EventEmitter<Error>();
constructor(private renderer: Renderer) {
}
build() {
if (!this.data.length) {
this.onError.emit(new Error('Data not available.'));
return;
}
let csvString = this.construct();
this.buildDownloader(csvString);
}
private getDocumentBody(): any {
return document.body;
}
private construct(): string {
let tabText = '';
const keys = Object.keys(this.data[0]);
if (!this.headers.length) {
// if no headers are passed, use data keys for headers
this.headers = keys;
}
this.headers.forEach(h => {
tabText += '"' + h + '",';
});
if (tabText.length > 0) {
tabText = tabText.slice(0, -1);
tabText += '\r\n';
}
this.data.forEach(d => {
keys.forEach(k => {
if (d.hasOwnProperty(k) && d[k] != null) {
tabText += '"' + d[k] + '",';
} else {
tabText += '"",';
}
});
tabText = tabText.slice(0, -1);
tabText += '\r\n';
});
return tabText;
}
private buildDownloader(data) {
let anchor = this.renderer.createElement(this.getDocumentBody(), 'a');
this.renderer.setElementStyle(anchor, 'visibility', 'hidden');
this.renderer.setElementAttribute(anchor, 'href', 'data:text/csv;charset=utf-8,' + encodeURIComponent(data));
this.renderer.setElementAttribute(anchor, 'target', '_blank');
this.renderer.setElementAttribute(anchor, 'download', this.fileName);
setTimeout(() => {
this.renderer.invokeElementMethod(anchor, 'click');
this.renderer.invokeElementMethod(anchor, 'remove');
}, 5);
}
}
@derekshi
Copy link
Author

derekshi commented Nov 1, 2016

Usage:
Put following in template:

   <csv-downloader [data]="dataObjectArray" [headers]="dataColumnNames"></csv-downloader>
  1. data binding must be array of object, such as

    [{
      storeId: "123",
      sales: "2343200"
      },
    ...
    ]
    
  2. headers must be array of strings. If headers is not provided, it will try to use data keys. In above example, it will use ["storeId", "sales"].

@mauriciovillalobos
Copy link

Very helpful, just what I needed, thanks!

@matiasfs12
Copy link

matiasfs12 commented Jan 25, 2018

image

http://jsonplaceholder.typicode.com/users

It draws my object on just one column, is that normal? Am i doing something wrong??

@dgashby
Copy link

dgashby commented Apr 22, 2018

Wow, this worked so easily first time and was simple to integrate. Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment