将数据导出为ex​​cel的正确方法?

时间:2016-11-09 20:37:06

标签: excel csv angular asp.net-core

我目前正在尝试以Excel或CSV格式从我的应用程序中导出一些数据。完成此任务的最佳方法是什么?我应该从后端导出,还是在数据客户端使用Angular 2中的库时导出?我的Web API 2控制器当前生成一个列表,然后将其作为JSON发送到前端。

一切正常,我只是在努力导出列表。

以下是我正在做的事情的样本

 [HttpGet]
 [Route("/api/preview/{item}")]
 public IActionResult Preview(string item)
 {      
     if (item!= null)
     {
         var preview = _context.dbPreview.FromSql("Exec sampleStoredProcedure {0}, 1", item).ToList();

         return Ok(preview);
     }
 }

这就是我生成发送到Angular 2的数据的方式。

如果有必要,我可以提供任何Angular 2代码但它只是一个普通的服务。不确定是否有一些库可以与Angular 2一起很好地进行导出。我已经看过javascript的一些东西,但alaSQL,但它似乎不适用于Angular 2。

有什么想法吗?

2 个答案:

答案 0 :(得分:1)

我已查看Element.getBoundingClientRect()的源代码,我认为您可以使用exportCSV代码导出数据的csv。

"技巧"是生成以data:text/csv;charset=utf-8开头的字符串,并由用户下载。

以下代码之类的东西应该对您有用(可能需要稍微修改它以使其适合您的数据)。

除下载方法外,大多数代码都是从PrimeNG复制的。该方法是从PrimeNG DataTable复制的。

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

@Component({
    selector: 'app-root',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.css']
})
export class AppComponent {
    title = 'app works!';

    csvSeparator = ';';

    value = [
        { name: 'A3', year: 2013, brand: 'Audi' },
        { name: 'Z3', year: 2015, brand: 'BMW' }
    ];

    columns = [
        { field: 'name', header: 'Name' },
        { field: 'year', header: 'Production data' },
        { field: 'brand', header: 'Brand' },
    ];

    constructor() {

        console.log(this.value);
        this.exportCSV('cars.csv'); // just for show casing --> later triggered by a click on a button
    }

    download(text, filename) {
        let element = document.createElement('a');
        element.setAttribute('href', 'data:text/csv;charset=utf-8,' + encodeURIComponent(text));
        element.setAttribute('download', filename);

        element.style.display = 'none';
        document.body.appendChild(element);

        element.click();

        document.body.removeChild(element);
    }

    exportCSV(filename) {
        let data = this.value, csv = '';
        // csv = "data:text/csv;charset=utf-8,";

        //headers
        for (let i = 0; i < this.columns.length; i++) {
            if (this.columns[i].field) {
                csv += this.columns[i].field;

                if (i < (this.columns.length - 1)) {
                    csv += this.csvSeparator;
                }
            }
        }

        //body        
        this.value.forEach((record, j) => {
            csv += '\n';
            for (let i = 0; i < this.columns.length; i++) {
                if (this.columns[i].field) {
                    console.log(record[this.columns[i].field]);
                    // resolveFieldData seems to check if field is nested e.g. data.something --> probably not needed
                    csv += record[this.columns[i].field]; //this.resolveFieldData(record, this.columns[i].field);

                    if (i < (this.columns.length - 1)) {
                        csv += this.csvSeparator;
                    }
                }
            }
        });
        // console.log(csv);
        // window.open(encodeURI(csv)); // doesn't display a filename!
        this.download(csv, filename);
    }

    // resolveFieldData(data: any, field: string): any {
    //     if(data && field) {
    //         if(field.indexOf('.') == -1) {
    //             return data[field];
    //         }
    //         else {
    //             let fields: string[] = field.split('.');
    //             let value = data;
    //             for(var i = 0, len = fields.length; i < len; ++i) {
    //                 value = value[fields[i]];
    //             }
    //             return value;
    //         }
    //     }
    //     else {
    //         return null;
    //     }
    // }


}

答案 1 :(得分:0)

AWolfs的回答让我走上正轨,但我做了一些调整以使其与Internet Explorer合作。

此函数将我的数组转换为我的csv文件的字符串。 (我必须创建一个新的对象,我的列标题)。然后我只是将我的服务生成的数据传递给函数,然后为我进行解析。对于更复杂的数据,我相信你需要做一些额外的逻辑,但我有基本的文字,所以这一切都适合我。

exportCSV(filename, CsvData) {
    let data = CsvData, csv = '';

    console.log(data);
    //headers
    for (let i = 0; i < this.columns.length; i++) {
        if (this.columns[i].field) {
            csv += this.columns[i].field;

            if (i < (this.columns.length - 1)) {
                csv += this.csvSeparator;
            }
        }
    }

    //body        
    CsvData.forEach((record, j) => {
        csv += '\n';
        for (let i = 0; i < this.columns.length; i++) {
            if (this.columns[i].field) {
                console.log(record[this.columns[i].field]);
                csv += record[this.columns[i].field]; 
                if (i < (this.columns.length - 1)) {
                    csv += this.csvSeparator;
                }
            }
        }
    });
    this.DownloadFile(csv, filename);
}

这与AWolfs的回答几乎相同,但我不得不对DownloadFile函数进行一些修改,以使其与其他浏览器一起使用。此函数只接受构成.CSV文件和文件名的巨大字符串。

 DownloadFile(text, filename) {
    console.log(text);
    var blob = new Blob([text], { type: 'text/csv;charset=utf-8;' });
    if (navigator.msSaveBlob) { // IE 10+
        navigator.msSaveBlob(blob, filename);
    }
    else //create a link and click it
    {
        var link = document.createElement("a");
        if (link.download !== undefined) // feature detection
        {
            // Browsers that support HTML5 download attribute
            var 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);
        }
    }
}

此代码需要清理,但我想更新我的问题,并为那些在同一件事上苦苦挣扎的人提供答案。这至少应该让你开始。这适用于Chrome和IE。

感谢。