3

I am looking for ways to convert a JSON object into CSV format using Angular. I came across this https://www.npmjs.com/package/jsonexport which is exactly the kind of thing I want to use, but I am unsure if I can actually use this with Angular (seems to node specific?) and if not, are there any ready made directives, etc out there that I could feed some JSON into to get CSV back.

Can anyone point me at some useful examples, I have had a look around and they seem to be few and far between and what I have found only seems to cope with very basic flat JSON structures.

Thanks

mindparse
  • 7,083
  • 17
  • 64
  • 146
  • there are several good javascript csv parsing libraries. CSV is pretty flat so not sure what your expectations are and you will likley need to do some mapping if your data isn't flat – charlietfl Aug 12 '15 at 15:24
  • http://ngmodules.org/modules/ng-csv ? – Alex Aug 12 '15 at 15:25
  • 2
    "are there any ready made directives" - this is really not what directives are for. – Sergio Tulentsev Aug 12 '15 at 15:25
  • 1
    possible duplicate of [How to convert JSON to CSV format and store in a variable](http://stackoverflow.com/questions/8847766/how-to-convert-json-to-csv-format-and-store-in-a-variable) – Jaka Konda Aug 12 '15 at 15:27

4 Answers4

3

Try this http://ngmodules.org/modules/ng-csv

For working example - https://asafdav.github.io/ng-csv/example/

Usage example js (taken from their docs)

Script

    var myapp = angular.module('myapp', ["ngSanitize", "ngCsv"]);

    myapp.controller('myctrl', function ($scope) {
        $scope.filename = "test";
        $scope.getArray = [{a: 1, b:2}, {a:3, b:4}];

      $scope.addRandomRow = function() {
        $scope.getArray.push({a: Math.floor((Math.random()*10)+1), b: Math.floor((Math.random()*10)+1)});
      };

      $scope.getHeader = function () {return ["A", "B"]};

      $scope.clickFn = function() {
        console.log("click click click");
      };
    });

Markup

<div ng-app="myapp">
    <div class="container" ng-controller="myctrl">

      <div class="page-header">
        <h1>ngCsv <small>example</small></h1>
      </div>

      <div class="form-group">
        <label for="filename">Filename </label>
        <input type="text" id="filename" class="form-control" ng-model="filename">
      </div>

      <div class="form-group">
        <label for="separator">Field separator</label>
        <input type="text" id="separator" class="form-control" ng-model="separator" ng-init="separator=','">
      </div>

      <div class="form-group">
        <label for="decimal-separator">Decimal separator</label>
        <input type="text" id="decimal-separator" class="form-control" ng-model="decimalSeparator" ng-init="decimalSeparator='.'">
      </div>            

      <button class="btn btn-default"
              ng-csv="getArray" filename="{{ filename }}.csv" field-separator="{{separator}}" decimal-separator="{{decimalSeparator}}"
              >Export to CSV</button>

      <button class="btn btn-default"
              ng-csv="getArray" csv-header="getHeader()" filename="{{ filename }}" field-separator="{{separator}}" decimal-separator="{{decimalSeparator}}"
              >Export to CSV with header</button>

      <button class="btn btn-default"
              ng-csv="getArray" csv-header="getHeader()" filename="{{ filename }}" field-separator="{{separator}}" decimal-separator="{{decimalSeparator}}"
              ng-click="clickFn()">Export with ng-click</button>

      <button class="btn btn-default"
              ng-csv="getArray" filename="{{ filename }}.csv" field-separator="{{separator}}" decimal-separator="{{decimalSeparator}}" add-bom="true"
        >With BOM</button>

      <button class="btn btn-default" ng-click="addRandomRow()">Add row</button>
    </div>
</div>
Alex
  • 34,123
  • 47
  • 189
  • 315
  • Thanks Alex, I did come across this (I should have said so in my OP) and tried it out, but in my case I have a complex JSON structure with nested levels and this module does not cope with it. I'll keep looking around! – mindparse Aug 12 '15 at 15:53
  • Is ng-csv able to handle objects that appear in the json? For example you have an order and in that order are positions with order items. – Andre Aus B Apr 25 '16 at 13:31
  • @Alex : can i use my nested object's attribute? or only it can do with simple json – Bhavesh Jariwala Jun 08 '16 at 13:10
2

You can export from JSON to CSV using this simple code. This code solve the many basic issues like, problems with the separator, custom heading, skip empty column and add - in place of the empty data for a particular column. Refer this github link to solve all the issue regarding CSV export in Angular.

https://github.com/marvin-aroza/Angular-csv-export

Consider this as you JSON data

jsonData : any = [{
    name : 'Berlin',
    age : '45',
    country : 'Spain',
    phone : '896514326'
  },
  {
    name : 'Professor',
    age : '42',
    country : 'spain'
  },
  {
    name : 'Tokyo',
    age : '35',
    phone : '854668244'
  },
  {
    name : 'Helsinki',
    phone : '35863297'
  }];

You can download you csv using these functions

exportCsv() {
    this.downloadFile(this.jsonData);
  }

  downloadFile(data, filename = 'data') {
    let arrHeader = ["name", "age", "country", "phone"];
    let csvData = this.ConvertToCSV(data, arrHeader);
    console.log(csvData)
    let blob = new Blob(['\ufeff' + csvData], { type: 'text/csv;charset=utf-8;' });
    let dwldLink = document.createElement("a");
    let url = URL.createObjectURL(blob);
    let isSafariBrowser = navigator.userAgent.indexOf('Safari') != -1 && navigator.userAgent.indexOf('Chrome') == -1;
    if (isSafariBrowser) {  //if Safari open in new window to save file with random filename.
      dwldLink.setAttribute("target", "_blank");
    }
    dwldLink.setAttribute("href", url);
    dwldLink.setAttribute("download", "sample.csv");
    dwldLink.style.visibility = "hidden";
    document.body.appendChild(dwldLink);
    dwldLink.click();
    document.body.removeChild(dwldLink);
  }

And to edit the format of the CSV you can add this function

ConvertToCSV(objArray, headerList) {
    console.log(objArray);
    console.log(headerList);
    let array = typeof objArray != 'object' ? JSON.parse(objArray) : objArray;
    let str = '';
    let row = 'S.No,';

    let newHeaders = ["Name", "Age", "Country", "Phone"];

    for (let index in newHeaders) {
      row += newHeaders[index] + ',';
    }
    row = row.slice(0, -1);
    str += row + '\r\n';
    for (let i = 0; i < array.length; i++) {
      let line = (i + 1) + '';
      for (let index in headerList) {
        let head = headerList[index];

        line += ',' + this.strRep(array[i][head]);
      }
      str += line + '\r\n';
    }
    return str;
  }

In case of values with comma, You can use this function to remove the comma and consider it as one single value

strRep(data) {
    if(typeof data == "string") {
      let newData = data.replace(/,/g, " ");
       return newData;
    }
    else if(typeof data == "undefined") {
      return "-";
    }
    else if(typeof data == "number") {
      return  data.toString();
    }
    else {
      return data;
    }
  }
0

There is no option to export sub-grid data in ui-grid. But we have another choice to export ui-grid and it's sub-grid data as .csv file by using FileSaver.js. I have created a Directive to get grid data/Json data and then format the data like a tree structure and then download .csv file by using FileSaver.js . It has a limit upto a nested grid.

    angular.module("exampleModule", [])
.controller('exampleController', function ($scope) {
                $scope.dataList = [
                    {
                        id: 1,
                        name: 'github',
                        price: '200$',
                        publisher: {
                            name: 'hieutran',
                            company: 'Dtag-VN'
                        },
                        nested:[
                         {
                            name: 'name1',
                            company: 'company1'
                        },
                        {
                            name: 'name2',
                            company: 'company2'
                        }]
                    },
                     {
                        id: 2,
                        name: 'twitter',
                        price: '500$',
                        publisher: {
                            name: 'twitter tran',
                            company: 'Canada'
                        },
                         nested:[]
                    },

                    {
                        id: 3,
                        name: 'google',
                        price: '300$',
                        publisher: {
                            name: 'tran',
                            company: 'Vietname'
                        },
                         nested:[
                         {
                            name: 'name3',
                            company: 'company3'
                        },
                        {
                            name: 'name4',
                            company: 'company4'
                        }]
                    }
                ]
            })
                            .directive("ngGridJsonExportExcel", function($timeout) {
                                return {
                                    restrict: "AE",
                                    scope: {
                                        data: "=",
                                        filename: "=?",
                                        reportFields: "=",
                                        nestedReportFields: "=",
                                        nestedDataProperty: "@"
                                    },
                                    link: function(scope, element) {
                                        scope.filename = !!scope.filename ? scope.filename : "export-excel";

                                        function generateFieldsAndHeaders(fieldsObject, fields, header) {
                                            _.forEach(fieldsObject, function(field, key) {
                                                if (!field || !key) {
                                                    throw new Error("error json report fields");
                                                }
                                                fields.push(key);
                                                header.push(field);
                                            });
                                            return {fields: fields, header: header};
                                        }
                                        var fieldsAndHeader = generateFieldsAndHeaders(scope.reportFields, [], []);
                                        var fields = fieldsAndHeader.fields, header = fieldsAndHeader.header;
                                        var nestedFieldsAndHeader = generateFieldsAndHeaders(scope.nestedReportFields, [], [""]);
                                        var nestedFields = nestedFieldsAndHeader.fields, nestedHeader = nestedFieldsAndHeader.header;
                                        function _convertToExcel(body, header) {
                                            return header + "\n" + body;
                                        }
                                        function _objectToString(object) {
                                            var output = "";
                                            _.forEach(object, function(value, key) {
                                                output += key + ":" + value + " ";
                                            });

                                            return "'" + output + "'";
                                        }
                                        function generateFieldValues(list, rowItems, dataItem) {
                                            _.forEach(list, function(field) {
                                                var data = "", fieldValue = "", curItem = null;
                                                if (field.indexOf(".")) {
                                                    field = field.split(".");
                                                    curItem = dataItem;
                                                    // deep access to obect property
                                                    _.forEach(field, function(prop) {
                                                        if (curItem !== null && curItem !== undefined) {
                                                            curItem = curItem[prop];
                                                        }
                                                    });
                                                    data = curItem;
                                                } else {
                                                    data = dataItem[field];
                                                }
                                                fieldValue = data !== null ? data : " ";
                                                if (fieldValue !== undefined && angular.isObject(fieldValue)) {
                                                    fieldValue = _objectToString(fieldValue);
                                                }
                                                rowItems.push(fieldValue);
                                            });
                                            return rowItems;
                                        }
                                        function _bodyData() {
                                            var body = "";

                                            _.forEach(scope.data, function(dataItem) {
                                                var rowItems = [];var nestedBody = "";
                                                rowItems = generateFieldValues(fields, rowItems, dataItem);
                                                //Nested Json body generation start 
                                                if (scope.nestedDataProperty && dataItem[scope.nestedDataProperty].length) {
                                                    _.forEach(dataItem[scope.nestedDataProperty], function(nestedDataItem) {
                                                        var nestedRowItems = [""];
                                                        nestedRowItems = generateFieldValues(nestedFields, nestedRowItems, nestedDataItem);
                                                        nestedBody += nestedRowItems.toString() + "\n";
                                                    });
                                                    var strData = _convertToExcel(nestedBody, nestedHeader);
                                                    body += rowItems.toString() + "\n" + strData;
                                                    ////Nested Json body generation end 
                                                } else {
                                                    body += rowItems.toString() + "\n";
                                                }
                                            });
                                            return body;
                                        }

                                        $timeout(function() {
                                            element.bind("click", function() {
                                                var bodyData = _bodyData();
                                                var strData = _convertToExcel(bodyData, header);
                                                var blob = new Blob([strData], {
                                                    type: "text/plain;charset=utf-8"
                                                });

                                                return saveAs(blob, [scope.filename + ".csv"]);
                                            });
                                        }, 1000);
                                    }
                                };
                            });

HTML code:

<button ng-json-export-excel data="dataList"  nested-data-property="nested" report-fields="{id: 'ID Heder', name: 'Name Header', price: 'Price Head',  'publisher.name': 'Publisher Head', 'publisher.company': 'Company Head'}" nested-report-fields="{name: 'Nested Name', company: 'Nested Company'}">Json Export</button>

Here is my plunker

VRavi
  • 1
  • 2
0
 generateUserCSV() {
    this.emailService.getAllEmail().subscribe((res) => { this.downloadFile(res, 'emails') })
  }


  downloadFile(data, filename = 'data') {
    let csvData = this.ConvertToCSV(data, ['email', 'firstname', 'lastname']);
    console.log(csvData)
    let blob = new Blob(['\ufeff' + csvData], { type: 'text/csv;charset=utf-8;' });
    let dwldLink = document.createElement("a");
    let url = URL.createObjectURL(blob);
    let isSafariBrowser = navigator.userAgent.indexOf('Safari') != -1 && navigator.userAgent.indexOf('Chrome') == -1;
    if (isSafariBrowser) {  //if Safari open in new window to save file with random filename.
      dwldLink.setAttribute("target", "_blank");
    }
    dwldLink.setAttribute("href", url);
    dwldLink.setAttribute("download", filename + ".csv");
    dwldLink.style.visibility = "hidden";
    document.body.appendChild(dwldLink);
    dwldLink.click();
    document.body.removeChild(dwldLink);
  }

  ConvertToCSV(objArray, headerList) {
    let array = typeof objArray != 'object' ? JSON.parse(objArray) : objArray;
    let str = '';
    let row = 'Index,';

    for (let index in headerList) {
      row += headerList[index] + ',';
    }
    row = row.slice(0, -1);
    str += row + '\r\n';
    for (let i = 0; i < array.length; i++) {
      let line = (i + 1) + '';
      for (let index in headerList) {
        let head = headerList[index];

        line += ',' + array[i][head];
      }
      str += line + '\r\n';
    }
    return str;
  }
  • While this code snippet may be the solution, [including an explanation](//meta.stackexchange.com/questions/114762/explaining-entirely-‌​code-based-answers) really helps to improve the quality of your post. Remember that you are answering the question for readers in the future, and those people might not know the reasons for your code suggestion. – Neo Anderson Sep 12 '20 at 20:57