4

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

4
  • 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 Commented Aug 12, 2015 at 15:24
  • ngmodules.org/modules/ng-csv ? Commented Aug 12, 2015 at 15:25
  • 2
    "are there any ready made directives" - this is really not what directives are for. Commented Aug 12, 2015 at 15:25
  • 1
    possible duplicate of How to convert JSON to CSV format and store in a variable Commented Aug 12, 2015 at 15:27

5 Answers 5

4

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;
    }
  }
Sign up to request clarification or add additional context in comments.

Comments

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>

3 Comments

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!
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.
@Alex : can i use my nested object's attribute? or only it can do with simple json
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;
  }

1 Comment

While this code snippet may be the solution, including an explanation 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.
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

1 Comment

how do you test this in jasmine? I've been hitting walls for this type of test
0
    downloadFile(data, filename = 'data') {
    const csvData = this.convertToCSV(data, ['name', 'age', 'average', 'approved', 'description']);
    const blob = new Blob(['\ufeff' + csvData], { type: 'text/csv;charset=utf-8;' });
    const downloadLink = document.createElement('a');
    const url = URL.createObjectURL(blob);
    const isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);

    if (isSafari) {
        downloadLink.setAttribute('target', '_blank');
    }

    downloadLink.setAttribute('href', url);
    downloadLink.setAttribute('download', `${filename}.csv`);
    downloadLink.style.visibility = 'hidden';
    document.body.appendChild(downloadLink);
    downloadLink.click();
    document.body.removeChild(downloadLink);
}

convertToCSV(dataArray, headers) {
    const array = Array.isArray(dataArray) ? dataArray : JSON.parse(dataArray);
    const headerRow = ['S.No', ...headers].join(',');
    const csvRows = array.map((item, index) => {
        const row = [index + 1, ...headers.map(header => item[header] || '')];
        return row.join(',');
    });

    return [headerRow, ...csvRows].join('\r\n');
}

2 Comments

Maybe add a description as to what you accomplished by way of an answer to the question.
As it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.