ANGULAR 5: 如何将数据导出为CSV文件

48

我是angular的初学者,目前正在使用Angular 5和Node v8.11.3。

我想要实现一个通用的函数,它以数据和标题作为参数,并将其输出为csv文件。

我创建了一个名为“FactureComponent”的组件,然后生成了一个服务叫做“DataService”,然后创建了一个getFactures函数,从模拟中检索我的项目列表,这个函数运行得非常好。

import { Component, OnInit } from '@angular/core';
import { DataService } from '../data.service';
import { FACTURES } from '../mock.factures';

@Component({
selector: 'app-facture',
templateUrl: './facture.component.html',
styleUrls: ['./facture.component.scss']
})
export class FactureComponent implements OnInit {

factures = [];
columns  = ["Id","Reference","Quantite","Prix Unitaire"];
btnText:  String = "Export CSV";

constructor(private _data: DataService) { }

ngOnInit() {
this.getFactures();
}
getFactures(){
this.factures=this._data.getFactures();
}
generateCSV(){
console.log("generate");
}
}

下面您将找到视图

<form>
<input type="submit" [value]="btnText" (click)="generateCSV()"/>
</form>

<table>
 <tr>
   <th *ngFor="let col of columns">
      {{col}}
   </th>
 </tr>
 <tr *ngFor="let facture of factures">
  <td>{{facture.id}}</td>     
  <td>{{facture.ref}}</td>
  <td>{{facture.quantite}}</td>
  <td>{{facture.prixUnitaire}}</td>
 </tr>
</table>

我想实现一个将视图显示的数据转换为CSV文件的功能。


这是在JavaScript中的实现方式,通过一些调整,应该很容易使其在TypeScript中运行。https://dev59.com/y2ox5IYBdhLWcg3w_JLd - Braden Brown
唯一可能不同的部分是 fs.WriteFile。 - Braden Brown
@BradenBrown 谢谢您的回复。 我们不能不使用 JavaScript 吗? - CHARAFI Saad
你只是想下载CSV文件吗?还是要将其保存到本地文件中? - Braden Brown
@BradenBrown 刚刚下载了 CSV 文件。 - CHARAFI Saad
我添加了一个答案。 - Braden Brown
2个回答

103

更新:

  1. 在项目目录中打开命令提示符。
  2. 通过输入 npm install --save file-saver 安装文件保存器。
  3. import { saveAs } from 'file-saver'; 导入到您的 .ts 文件中。
  4. 以下是基于新导入的更新代码。
downloadFile(data: any) {
    const replacer = (key, value) => value === null ? '' : value; // specify how you want to handle null values here
    const header = Object.keys(data[0]);
    let csv = data.map(row => header.map(fieldName => JSON.stringify(row[fieldName], replacer)).join(','));
    csv.unshift(header.join(','));
    let csvArray = csv.join('\r\n');

    var blob = new Blob([csvArray], {type: 'text/csv' })
    saveAs(blob, "myFile.csv");
}

感谢这个答案提供将对象转换为CSV格式的方法。

以下是使用该方法的步骤:

downloadFile(data: any) {
  const replacer = (key, value) => (value === null ? '' : value); // specify how you want to handle null values here
  const header = Object.keys(data[0]);
  const csv = data.map((row) =>
    header
      .map((fieldName) => JSON.stringify(row[fieldName], replacer))
      .join(',')
  );
  csv.unshift(header.join(','));
  const csvArray = csv.join('\r\n');

  const a = document.createElement('a');
  const blob = new Blob([csvArray], { type: 'text/csv' });
  const url = window.URL.createObjectURL(blob);

  a.href = url;
  a.download = 'myFile.csv';
  a.click();
  window.URL.revokeObjectURL(url);
  a.remove();
}

如果我找到了更好的方法,我会后续添加。


7
对于 *.ts 文件,请添加 npm install @types/file-saver --save-dev - Kris Jobs
12
安装@types/file-saver类型定义库,运行命令为npm install @types/file-saver --save-dev - tom10271
1
此外,可以通过以下方式安装TypeScript定义:npm install @types/file-saver --save-dev - SuperStar518
11
现在导入的方法已经改变了 - import { saveAs } from 'file-saver'; - SuperStar518
我运行了npm install @types/file-saver --save-dev,从'file-saver'导入{ saveAs },但它仍然显示“找不到模块文件保存器”。 - Scoopex
2
你可以简化那个null检查: (key: string, value: any) => value ?? ''; - Janos Vinceller

18

我的解决方案目前是为保存创建一个服务(我从Changhui Xu @ codeburst得到这个方法)。不需要安装任何软件包...

import { Injectable } from '@angular/core';

declare global {
    interface Navigator {
        msSaveBlob?: (blob: any, defaultName?: string) => boolean
    }
}

@Injectable({
    providedIn: 'root',
})
export class CsvDataService {
    exportToCsv(filename: string, rows: object[]) {
      if (!rows || !rows.length) {
        return;
      }
      const separator = ',';
      const keys = Object.keys(rows[0]);
      const csvContent =
        keys.join(separator) +
        '\n' +
        rows.map(row => {
          return keys.map(k => {
            let cell = row[k] === null || row[k] === undefined ? '' : row[k];
            cell = cell instanceof Date
              ? cell.toLocaleString()
              : cell.toString().replace(/"/g, '""');
            if (cell.search(/("|,|\n)/g) >= 0) {
              cell = `"${cell}"`;
            }
            return cell;
          }).join(separator);
        }).join('\n');
  
      const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' });
      if (navigator.msSaveBlob) { // IE 10+
        navigator.msSaveBlob(blob, filename);
      } else {
        const link = document.createElement('a');
        if (link.download !== undefined) {
          // Browsers that support HTML5 download attribute
          const url = URL.createObjectURL(blob);
          link.setAttribute('href', url);
          link.setAttribute('download', filename);
          link.style.visibility = 'hidden';
          document.body.appendChild(link);
          link.click();
          document.body.removeChild(link);
        }
      }
    }
  }

然后我将这个服务注入到我的组件中。它随后调用了这个服务:


  constructor(private csvService :CsvDataService) {}

  saveAsCSV() {
    if(this.reportLines.filteredData.length > 0){
      const items: CsvData[] = [];

      this.reportLines.filteredData.forEach(line => {
        let reportDate = new Date(report.date);
        let csvLine: CsvData = {
          date: `${reportDate.getDate()}/${reportDate.getMonth()+1}/${reportDate.getFullYear()}`,
          laborerName: line.laborerName,
          machineNumber: line.machineNumber,
          machineName: line.machineName,
          workingHours: line.hours,
          description: line.description
        }
        items.push(csvLine); 
      });

      this.csvService.exportToCsv('myCsvDocumentName.csv', items);
    }
    
  }

此解决方案在字符串的开头和结尾添加了额外的引号。 - dlporter98
1
请注意,从 2022 年起,msSaveBlob 不再作为浏览器导航器的一部分提供:https://dev59.com/ElEG5IYBdhLWcg3wQICq - glenatron
3
@glenatron,我已经更新答案,包括你提供的全局声明。 - James D

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接