├── .gitignore ├── bower.json ├── example.html ├── example.es5.html ├── package.json ├── README.md ├── docs ├── styles.css └── index.html ├── xls-export.js ├── xls-export.es5.js ├── xls-export.es5.js.map └── example-dataset.js /.gitignore: -------------------------------------------------------------------------------- 1 | bower.json 2 | bower_components/ 3 | .eslintrc.js 4 | node_modules/ 5 | .DS_Store -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "xlsexport", 3 | "homepage": "https://github.com/deblanco/xlsExport", 4 | "authors": [ 5 | "Daniel Blanco Parla " 6 | ], 7 | "description": "JS library for exporting object arrays to Excel XLS and CSV", 8 | "main": "xls-export.js", 9 | "keywords": [ 10 | "xls", 11 | "csv", 12 | "excel", 13 | "export", 14 | "objects", 15 | "arrays" 16 | ], 17 | "license": "MIT" 18 | } 19 | -------------------------------------------------------------------------------- /example.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | xls-export sample page 6 | 7 | 8 | 9 | 10 | 11 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /example.es5.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | xls-export sample page 6 | 7 | 8 | 9 | 10 | 11 | 12 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "xlsexport", 3 | "version": "1.5.2", 4 | "description": "JS library for export array of objects to Excel XLS or CSV", 5 | "main": "xls-export.js", 6 | "scripts": { 7 | "babel": "babel --presets es2015 xls-export.js -o xls-export.es5.js" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/deblanco/xlsExport.git" 12 | }, 13 | "keywords": [ 14 | "excel", 15 | "array", 16 | "javascript", 17 | "xls", 18 | "csv", 19 | "objects", 20 | "download" 21 | ], 22 | "author": "Daniel Blanco Parla", 23 | "license": "MIT", 24 | "bugs": { 25 | "url": "https://github.com/deblanco/xlsExport/issues" 26 | }, 27 | "homepage": "https://github.com/deblanco/xlsExport#readme", 28 | "devDependencies": { 29 | "babel-cli": "^6.26.0", 30 | "babel-core": "^6.26.0", 31 | "babel-loader": "^7.1.2", 32 | "babel-preset-es2015": "^6.24.1", 33 | "babel-preset-stage-3": "^6.24.1", 34 | "eslint": "^4.12.1", 35 | "eslint-config-airbnb-base": "^12.1.0", 36 | "eslint-plugin-import": "^2.8.0" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # xlsexport 2 | 3 | Javascript library for exporting object arrays to Excel XLS and CSV. 4 | 5 | ## Installation 6 | 7 | Clone or download the Github repo or via bower: 8 | 9 | ```bash 10 | bower install xlsexport 11 | 12 | or 13 | 14 | npm install xlsexport 15 | ``` 16 | 17 | ## Usage 18 | 19 | xlsExport is defined as a class, so has to be instantiated with **data** (objects array) and an optional **title**. 20 | 21 | ```javascript 22 | var xls = new XlsExport([..., Object], String); 23 | ``` 24 | Since Chromium(v61) supports ES6 Modules, XlsExport is available with 'import' syntax 😎. For older browsers I also include an ES5 version inside the package. 25 | 26 | ### Methods: 27 | - *exportToXLS(String fileName)*: convert data and force download of a Excel XLS file. 28 | - *exportToCSV(String fileName)*: convert data separate by semi-colons and force download of a CSV file. 29 | 30 | *fileName parameter is **optional**, if it's not defined, the file will be named "export.xls".* 31 | 32 | ### Example 33 | ```javascript 34 | import XlsExport from './xls-export.js'; 35 | 36 | var xls = new XlsExport([..., Object], String); 37 | xls.exportToXLS('export2017.xls'); 38 | xls.exportToCSV('export2017.xls'); 39 | ``` 40 | 41 | ### Demo: https://jsfiddle.net/3xvb2g5w/ 42 | 43 | --- 44 | 45 | License: MIT -------------------------------------------------------------------------------- /docs/styles.css: -------------------------------------------------------------------------------- 1 | @import url('https://fonts.googleapis.com/css?family=Open+Sans'); 2 | 3 | * { 4 | box-sizing: border-box; 5 | } 6 | 7 | html, body { 8 | background: #232526; 9 | /* fallback for old browsers */ 10 | background: -webkit-linear-gradient(to right, #414345, #232526); 11 | /* Chrome 10-25, Safari 5.1-6 */ 12 | background: linear-gradient(to right, #414345, #232526); 13 | /* W3C, IE 10+/ Edge, Firefox 16+, Chrome 26+, Opera 12+, Safari 7+ */ 14 | font-family: 'Open Sans', sans-serif; 15 | } 16 | 17 | h1 { 18 | font-size: 1.5em; 19 | } 20 | 21 | a { 22 | text-decoration: none; 23 | color: #424242; 24 | opacity: 0.75; 25 | } 26 | 27 | a:hover { 28 | opacity: 1; 29 | } 30 | 31 | #wrapper { 32 | margin: 5em auto 0 auto; 33 | max-width: 960px; 34 | color: #fff; 35 | } 36 | 37 | @media (max-width: 480px) { 38 | #wrapper { 39 | margin: 0; 40 | } 41 | } 42 | 43 | header { 44 | margin: 1em; 45 | } 46 | 47 | footer { 48 | display: flex; 49 | flex-flow: row nowrap; 50 | justify-content: space-between; 51 | font-size: 0.9em; 52 | margin: 1em 0; 53 | } 54 | 55 | #content { 56 | background: #fff; 57 | border-radius: 1px; 58 | box-shadow: 0 10px 20px rgba(0,0,0,0.19), 0 6px 6px rgba(0,0,0,0.23); 59 | color: #424242; 60 | padding: 0.5em 1em; 61 | position: relative; 62 | } 63 | 64 | #badges { 65 | display: flex; 66 | flex-flow: row nowrap; 67 | justify-content: flex-end; 68 | } 69 | 70 | #badges > * { 71 | margin-left: 0.5em; 72 | } 73 | 74 | .code { 75 | margin: 1em; 76 | padding: 1em; 77 | border-radius: 3px; 78 | background: #424242; 79 | color: #fff; 80 | } 81 | 82 | .emoji { 83 | height: 18px; 84 | margin-left: 2px; 85 | } 86 | -------------------------------------------------------------------------------- /xls-export.js: -------------------------------------------------------------------------------- 1 | /** 2 | * __ ___ _____ _ 3 | * \ \/ / |___| ____|_ ___ __ ___ _ __| |_ 4 | * \ /| / __| _| \ \/ / '_ \ / _ \| '__| __| 5 | * / \| \__ \ |___ > <| |_) | (_) | | | |_ 6 | * /_/\_\_|___/_____/_/\_\ .__/ \___/|_| \__| 7 | * |_| 8 | * 6/12/2017 9 | * Daniel Blanco Parla 10 | * https://github.com/deblanco/xlsExport 11 | */ 12 | 13 | class XlsExport { 14 | // data: array of objects with the data for each row of the table 15 | // name: title for the worksheet 16 | constructor(data, title = 'Worksheet') { 17 | // input validation: new xlsExport([], String) 18 | if (!Array.isArray(data) || (typeof title !== 'string' || Object.prototype.toString.call(title) !== '[object String]')) { 19 | throw new Error('Invalid input types: new xlsExport(Array [], String)'); 20 | } 21 | 22 | this._data = data; 23 | this._title = title; 24 | } 25 | 26 | set setData(data) { 27 | if (!Array.isArray(data)) throw new Error('Invalid input type: setData(Array [])'); 28 | 29 | this._data = data; 30 | } 31 | 32 | get getData() { 33 | return this._data; 34 | } 35 | 36 | exportToXLS(fileName = 'export.xls', rtl = false) { 37 | if (typeof fileName !== 'string' || Object.prototype.toString.call(fileName) !== '[object String]') { 38 | throw new Error('Invalid input type: exportToCSV(String)'); 39 | } 40 | 41 | var TEMPLATE_XLS_val = ` 42 | 43 | 44 | 53 | {table}`; 54 | 55 | const TEMPLATE_XLS = TEMPLATE_XLS_val; 56 | 57 | const MIME_XLS = 'application/vnd.ms-excel;base64,'; 58 | 59 | const parameters = { 60 | title: this._title, 61 | table: this.objectToTable(), 62 | }; 63 | const computeOutput = TEMPLATE_XLS.replace(/{(\w+)}/g, (x, y) => parameters[y]); 64 | 65 | const computedXLS = new Blob([computeOutput], { 66 | type: MIME_XLS, 67 | }); 68 | const xlsLink = window.URL.createObjectURL(computedXLS); 69 | this.downloadFile(xlsLink, fileName); 70 | } 71 | 72 | exportToCSV(fileName = 'export.csv') { 73 | if (typeof fileName !== 'string' || Object.prototype.toString.call(fileName) !== '[object String]') { 74 | throw new Error('Invalid input type: exportToCSV(String)'); 75 | } 76 | const computedCSV = new Blob([this.objectToSemicolons()], { 77 | type: 'text/csv;charset=utf-8', 78 | }); 79 | const csvLink = window.URL.createObjectURL(computedCSV); 80 | this.downloadFile(csvLink, fileName); 81 | } 82 | 83 | downloadFile(output, fileName) { 84 | const link = document.createElement('a'); 85 | document.body.appendChild(link); 86 | link.download = fileName; 87 | link.href = output; 88 | link.click(); 89 | } 90 | 91 | toBase64(string) { 92 | return window.btoa(unescape(encodeURIComponent(string))); 93 | } 94 | 95 | objectToTable() { 96 | // extract keys from the first object, will be the title for each column 97 | const colsHead = `${Object.keys(this._data[0]).map(key => `${key}`).join('')}`; 98 | 99 | const colsData = this._data.map(obj => [` 100 | ${Object.keys(obj).map(col => `${(obj[col] === 0 || obj[col]) ? obj[col] : ''}`).join('')} 101 | `]) // 'null' values not showed but zero value is showed 102 | .join(''); 103 | 104 | return `${colsHead}${colsData}
`.trim(); // remove spaces... 105 | } 106 | 107 | objectToSemicolons() { 108 | const colsHead = Object.keys(this._data[0]).map(key => [key]).join(';'); 109 | const colsData = this._data.map(obj => [ // obj === row 110 | Object.keys(obj).map(col => [ 111 | obj[col], // row[column] 112 | ]).join(';'), // join the row with ';' 113 | ]).join('\n'); // end of row 114 | 115 | return `${colsHead}\n${colsData}`; 116 | } 117 | } 118 | 119 | export default XlsExport; // comment this line to babelize 120 | -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | xlsexport.js 6 | 7 | 8 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 |
18 |

xlsexport.js

19 |
zero-dependency library for exporting object arrays to Excel XLS and CSV.
20 |
21 |
22 |
23 | 24 | 25 | 26 |
27 |

Installation 🚀

28 |
29 | Clone or download the Github repo or via npm: 30 |
31 | npm install xlsexport 32 |
33 |
34 |

Usage 👩‍🔧

35 |
36 | xlsExport is defined as a class, and has to be instantiated with data (objects array) and an optional title. 37 |
38 | var xls = new XlsExport([..., Object], String); 39 |
40 | Since Chromium(v61) supports ES6 Modules, XlsExport is available with 'import' syntax 😎. For older browsers I also include 41 | an ES5 version inside the package. 42 |
43 |

Methods 📖

44 |
45 |
    46 |
  • 47 | exportToXLS(String fileName): convert data and force download of a Excel XLS file.
  • 48 |
  • 49 | exportToCSV(String fileName): convert data separate by semi-colons and force download of a CSV 50 | file. 51 |
  • 52 |
53 | fileName parameter is optional, if it's not defined, the file will be named "export.xls". 54 |
55 |

Example 🛫

56 |
57 | import XlsExport from './xls-export.js'; 58 |
59 |
var xls = new XlsExport([..., Object], String); 60 |
xls.exportToXLS('export2017.xls'); 61 |
xls.exportToCSV('export2017.xls'); 62 |
63 |

Todo ✅

64 |
65 |
    66 |
  • Support for node.js
  • 67 |
  • Support for more formats: .ods, enchance .xls, ...
  • 68 |
69 |
70 |
71 | 85 |
86 |
87 | 93 | 94 | 95 | -------------------------------------------------------------------------------- /xls-export.es5.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); 4 | 5 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 6 | 7 | /** 8 | * __ ___ _____ _ 9 | * \ \/ / |___| ____|_ ___ __ ___ _ __| |_ 10 | * \ /| / __| _| \ \/ / '_ \ / _ \| '__| __| 11 | * / \| \__ \ |___ > <| |_) | (_) | | | |_ 12 | * /_/\_\_|___/_____/_/\_\ .__/ \___/|_| \__| 13 | * |_| 14 | * 6/12/2017 15 | * Daniel Blanco Parla 16 | * https://github.com/deblanco/xlsExport 17 | */ 18 | 19 | var XlsExport = function () { 20 | // data: array of objects with the data for each row of the table 21 | // name: title for the worksheet 22 | function XlsExport(data) { 23 | var title = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'Worksheet'; 24 | 25 | _classCallCheck(this, XlsExport); 26 | 27 | // input validation: new xlsExport([], String) 28 | if (!Array.isArray(data) || typeof title !== 'string' || Object.prototype.toString.call(title) !== '[object String]') { 29 | throw new Error('Invalid input types: new xlsExport(Array [], String)'); 30 | } 31 | 32 | this._data = data; 33 | this._title = title; 34 | } 35 | 36 | _createClass(XlsExport, [{ 37 | key: 'exportToXLS', 38 | value: function exportToXLS() { 39 | var fileName = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'export.xls'; 40 | 41 | if (typeof fileName !== 'string' || Object.prototype.toString.call(fileName) !== '[object String]') { 42 | throw new Error('Invalid input type: exportToCSV(String)'); 43 | } 44 | 45 | var TEMPLATE_XLS = '\n \n \n \n {table}'; 46 | var MIME_XLS = 'application/vnd.ms-excel;base64,'; 47 | 48 | var parameters = { 49 | title: this._title, 50 | table: this.objectToTable() 51 | }; 52 | var computeOutput = TEMPLATE_XLS.replace(/{(\w+)}/g, function (x, y) { 53 | return parameters[y]; 54 | }); 55 | 56 | var computedXLS = new Blob([computeOutput], { 57 | type: MIME_XLS 58 | }); 59 | var xlsLink = window.URL.createObjectURL(computedXLS); 60 | this.downloadFile(xlsLink, fileName); 61 | } 62 | }, { 63 | key: 'exportToCSV', 64 | value: function exportToCSV() { 65 | var fileName = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'export.csv'; 66 | 67 | if (typeof fileName !== 'string' || Object.prototype.toString.call(fileName) !== '[object String]') { 68 | throw new Error('Invalid input type: exportToCSV(String)'); 69 | } 70 | var computedCSV = new Blob([this.objectToSemicolons()], { 71 | type: 'text/csv;charset=utf-8' 72 | }); 73 | var csvLink = window.URL.createObjectURL(computedCSV); 74 | this.downloadFile(csvLink, fileName); 75 | } 76 | }, { 77 | key: 'downloadFile', 78 | value: function downloadFile(output, fileName) { 79 | var link = document.createElement('a'); 80 | document.body.appendChild(link); 81 | link.download = fileName; 82 | link.href = output; 83 | link.click(); 84 | } 85 | }, { 86 | key: 'toBase64', 87 | value: function toBase64(string) { 88 | return window.btoa(unescape(encodeURIComponent(string))); 89 | } 90 | }, { 91 | key: 'objectToTable', 92 | value: function objectToTable() { 93 | // extract keys from the first object, will be the title for each column 94 | var colsHead = '' + Object.keys(this._data[0]).map(function (key) { 95 | return '' + key + ''; 96 | }).join('') + ''; 97 | 98 | var colsData = this._data.map(function (obj) { 99 | return ['\n ' + Object.keys(obj).map(function (col) { 100 | return '' + (obj[col] ? obj[col] : '') + ''; 101 | }).join('') + '\n ']; 102 | }) // 'null' values not showed 103 | .join(''); 104 | 105 | return ('' + colsHead + colsData + '
').trim(); // remove spaces... 106 | } 107 | }, { 108 | key: 'objectToSemicolons', 109 | value: function objectToSemicolons() { 110 | var colsHead = Object.keys(this._data[0]).map(function (key) { 111 | return [key]; 112 | }).join(';'); 113 | var colsData = this._data.map(function (obj) { 114 | return [// obj === row 115 | Object.keys(obj).map(function (col) { 116 | return [obj[col]]; 117 | } // row[column] 118 | ).join(';')]; 119 | } // join the row with ';' 120 | ).join('\n'); // end of row 121 | 122 | return colsHead + '\n' + colsData; 123 | } 124 | }, { 125 | key: 'setData', 126 | set: function set(data) { 127 | if (!Array.isArray(data)) throw new Error('Invalid input type: setData(Array [])'); 128 | 129 | this._data = data; 130 | } 131 | }, { 132 | key: 'getData', 133 | get: function get() { 134 | return this._data; 135 | } 136 | }]); 137 | 138 | return XlsExport; 139 | }(); 140 | 141 | // export default XlsExport; // comment this line to babelize 142 | -------------------------------------------------------------------------------- /xls-export.es5.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["webpack:///webpack/bootstrap 97f71bbac360f8da949b","webpack:///./xls-export.js"],"names":["XlsExport","data","title","Array","isArray","Object","prototype","toString","call","Error","_data","_title","fileName","TEMPLATE_XLS","MIME_XLS","parameters","table","objectToTable","computeOutput","replace","x","y","downloadFile","toBase64","MIME_CSV","encodeURIComponent","objectToSemicolons","output","link","document","createElement","body","appendChild","download","href","click","string","window","btoa","unescape","colsHead","keys","map","key","join","colsData","obj","col","trim"],"mappings":"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","file":"xls-export.es5.js","sourcesContent":[" \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, {\n \t\t\t\tconfigurable: false,\n \t\t\t\tenumerable: true,\n \t\t\t\tget: getter\n \t\t\t});\n \t\t}\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 0);\n\n\n\n// WEBPACK FOOTER //\n// webpack/bootstrap 97f71bbac360f8da949b","/**\n * __ ___ _____ _\n * \\ \\/ / |___| ____|_ ___ __ ___ _ __| |_\n * \\ /| / __| _| \\ \\/ / '_ \\ / _ \\| '__| __|\n * / \\| \\__ \\ |___ > <| |_) | (_) | | | |_\n * /_/\\_\\_|___/_____/_/\\_\\ .__/ \\___/|_| \\__|\n * |_|\n * 6/12/2017\n * Daniel Blanco Parla\n * https://github.com/deblanco/xlsExport\n */\n\nclass XlsExport {\n // data: array of objects with the data for each row of the table\n // name: title for the worksheet\n constructor(data, title = 'Worksheet') {\n // input validation: new xlsExport([], String)\n if (!Array.isArray(data) || (typeof title !== 'string' || Object.prototype.toString.call(title) !== '[object String]')) { throw new Error('Invalid input types: new xlsExport(Array [], String)'); }\n\n this._data = data;\n this._title = title;\n }\n\n set setData(data) {\n if (!Array.isArray(data)) throw new Error('Invalid input type: setData(Array [])');\n\n this._data = data;\n }\n\n get getData() {\n return this._data;\n }\n\n exportToXLS(fileName = 'export.xls') {\n if (typeof fileName !== 'string' || Object.prototype.toString.call(fileName) !== '[object String]') { throw new Error('Invalid input type: exportToCSV(String)'); }\n\n const TEMPLATE_XLS = `\n \n \n \n {table}`;\n const MIME_XLS = 'data:application/vnd.ms-excel;base64,';\n\n const parameters = { title: this._title, table: this.objectToTable() };\n const computeOutput = TEMPLATE_XLS.replace(/{(\\w+)}/g, (x, y) => parameters[y]);\n\n this.downloadFile(MIME_XLS + this.toBase64(computeOutput), fileName);\n }\n\n exportToCSV(fileName = 'export.csv') {\n if (typeof fileName !== 'string' || Object.prototype.toString.call(fileName) !== '[object String]') { throw new Error('Invalid input type: exportToCSV(String)'); }\n\n const MIME_CSV = 'data:attachament/csv,';\n this.downloadFile(MIME_CSV + encodeURIComponent(this.objectToSemicolons()), fileName);\n }\n\n downloadFile(output, fileName) {\n const link = document.createElement('a');\n document.body.appendChild(link);\n link.download = fileName;\n link.href = output;\n link.click();\n }\n\n toBase64(string) {\n return window.btoa(unescape(encodeURIComponent(string)));\n }\n\n objectToTable() {\n // extract keys from the first object, will be the title for each column\n const colsHead = `${Object.keys(this._data[0]).map(key => `${key}`).join('')}`;\n\n const colsData = this._data.map(obj => [`\n ${Object.keys(obj).map(col => `${obj[col] ? obj[col] : ''}`).join('')}\n `]) // 'null' values not showed\n .join('');\n\n return `${colsHead}${colsData}
`.trim(); // remove spaces...\n }\n\n objectToSemicolons() {\n const colsHead = Object.keys(this._data[0]).map(key => [key]).join(';');\n const colsData = this._data.map(obj => [ // obj === row\n Object.keys(obj).map(col => [\n obj[col], // row[column]\n ]).join(';'), // join the row with ';'\n ]).join('\\n'); // end of row\n\n return `${colsHead}\\n${colsData}`;\n }\n}\n\n// export default XlsExport; // comment this line to babelize\n\n\n\n// WEBPACK FOOTER //\n// ./xls-export.js"],"sourceRoot":""} -------------------------------------------------------------------------------- /example-dataset.js: -------------------------------------------------------------------------------- 1 | const dataSample = [{ 2 | "symbol": "IBM", 3 | "date": "Aug 2004", 4 | "price": 78.17 5 | }, 6 | { 7 | "symbol": "IBM", 8 | "date": "Sep 2004", 9 | "price": 79.13 10 | }, 11 | { 12 | "symbol": "IBM", 13 | "date": "Oct 2004", 14 | "price": 82.84 15 | }, 16 | { 17 | "symbol": "IBM", 18 | "date": "Nov 2004", 19 | "price": 87.15 20 | }, 21 | { 22 | "symbol": "IBM", 23 | "date": "Dec 2004", 24 | "price": 91.16 25 | }, 26 | { 27 | "symbol": "IBM", 28 | "date": "Jan 2005", 29 | "price": 86.39 30 | }, 31 | { 32 | "symbol": "IBM", 33 | "date": "Feb 2005", 34 | "price": 85.78 35 | }, 36 | { 37 | "symbol": "IBM", 38 | "date": "Mar 2005", 39 | "price": 84.66 40 | }, 41 | { 42 | "symbol": "IBM", 43 | "date": "Apr 2005", 44 | "price": 70.77 45 | }, 46 | { 47 | "symbol": "IBM", 48 | "date": "May 2005", 49 | "price": 70.18 50 | }, 51 | { 52 | "symbol": "IBM", 53 | "date": "Jun 2005", 54 | "price": 68.93 55 | }, 56 | { 57 | "symbol": "IBM", 58 | "date": "Jul 2005", 59 | "price": 77.53 60 | }, 61 | { 62 | "symbol": "IBM", 63 | "date": "Aug 2005", 64 | "price": 75.07 65 | }, 66 | { 67 | "symbol": "IBM", 68 | "date": "Sep 2005", 69 | "price": 74.7 70 | }, 71 | { 72 | "symbol": "IBM", 73 | "date": "Oct 2005", 74 | "price": 76.25 75 | }, 76 | { 77 | "symbol": "IBM", 78 | "date": "Nov 2005", 79 | "price": 82.98 80 | }, 81 | { 82 | "symbol": "IBM", 83 | "date": "Dec 2005", 84 | "price": 76.73 85 | }, 86 | { 87 | "symbol": "IBM", 88 | "date": "Jan 2006", 89 | "price": 75.89 90 | }, 91 | { 92 | "symbol": "IBM", 93 | "date": "Feb 2006", 94 | "price": 75.09 95 | }, 96 | { 97 | "symbol": "IBM", 98 | "date": "Mar 2006", 99 | "price": 77.17 100 | }, 101 | { 102 | "symbol": "IBM", 103 | "date": "Apr 2006", 104 | "price": 77.05 105 | }, 106 | { 107 | "symbol": "IBM", 108 | "date": "May 2006", 109 | "price": 75.04 110 | }, 111 | { 112 | "symbol": "IBM", 113 | "date": "Jun 2006", 114 | "price": 72.15 115 | }, 116 | { 117 | "symbol": "IBM", 118 | "date": "Jul 2006", 119 | "price": 72.7 120 | }, 121 | { 122 | "symbol": "IBM", 123 | "date": "Aug 2006", 124 | "price": 76.35 125 | }, 126 | { 127 | "symbol": "IBM", 128 | "date": "Sep 2006", 129 | "price": 77.26 130 | }, 131 | { 132 | "symbol": "IBM", 133 | "date": "Oct 2006", 134 | "price": 87.06 135 | }, 136 | { 137 | "symbol": "IBM", 138 | "date": "Nov 2006", 139 | "price": 86.95 140 | }, 141 | { 142 | "symbol": "IBM", 143 | "date": "Dec 2006", 144 | "price": 91.9 145 | }, 146 | { 147 | "symbol": "IBM", 148 | "date": "Jan 2007", 149 | "price": 93.79 150 | }, 151 | { 152 | "symbol": "IBM", 153 | "date": "Feb 2007", 154 | "price": 88.18 155 | }, 156 | { 157 | "symbol": "IBM", 158 | "date": "Mar 2007", 159 | "price": 89.44 160 | }, 161 | { 162 | "symbol": "IBM", 163 | "date": "Apr 2007", 164 | "price": 96.98 165 | }, 166 | { 167 | "symbol": "IBM", 168 | "date": "May 2007", 169 | "price": 101.54 170 | }, 171 | { 172 | "symbol": "IBM", 173 | "date": "Jun 2007", 174 | "price": 100.25 175 | }, 176 | { 177 | "symbol": "IBM", 178 | "date": "Jul 2007", 179 | "price": 105.4 180 | }, 181 | { 182 | "symbol": "IBM", 183 | "date": "Aug 2007", 184 | "price": 111.54 185 | }, 186 | { 187 | "symbol": "IBM", 188 | "date": "Sep 2007", 189 | "price": 112.6 190 | }, 191 | { 192 | "symbol": "IBM", 193 | "date": "Oct 2007", 194 | "price": 111 195 | }, 196 | { 197 | "symbol": "IBM", 198 | "date": "Nov 2007", 199 | "price": 100.9 200 | }, 201 | { 202 | "symbol": "IBM", 203 | "date": "Dec 2007", 204 | "price": 103.7 205 | }, 206 | { 207 | "symbol": "IBM", 208 | "date": "Jan 2008", 209 | "price": 102.75 210 | }, 211 | { 212 | "symbol": "IBM", 213 | "date": "Feb 2008", 214 | "price": 109.64 215 | }, 216 | { 217 | "symbol": "IBM", 218 | "date": "Mar 2008", 219 | "price": 110.87 220 | }, 221 | { 222 | "symbol": "IBM", 223 | "date": "Apr 2008", 224 | "price": 116.23 225 | }, 226 | { 227 | "symbol": "IBM", 228 | "date": "May 2008", 229 | "price": 125.14 230 | }, 231 | { 232 | "symbol": "IBM", 233 | "date": "Jun 2008", 234 | "price": 114.6 235 | }, 236 | { 237 | "symbol": "IBM", 238 | "date": "Jul 2008", 239 | "price": 123.74 240 | }, 241 | { 242 | "symbol": "IBM", 243 | "date": "Aug 2008", 244 | "price": 118.16 245 | }, 246 | { 247 | "symbol": "IBM", 248 | "date": "Sep 2008", 249 | "price": 113.53 250 | }, 251 | { 252 | "symbol": "IBM", 253 | "date": "Oct 2008", 254 | "price": 90.24 255 | }, 256 | { 257 | "symbol": "IBM", 258 | "date": "Jan 2009", 259 | "price": 89.46 260 | }, 261 | { 262 | "symbol": "IBM", 263 | "date": "Feb 2009", 264 | "price": 90.32 265 | }, 266 | { 267 | "symbol": "IBM", 268 | "date": "Mar 2009", 269 | "price": 95.09 270 | }, 271 | { 272 | "symbol": "IBM", 273 | "date": "Apr 2009", 274 | "price": 101.29 275 | }, 276 | { 277 | "symbol": "IBM", 278 | "date": "May 2009", 279 | "price": 104.85 280 | }, 281 | { 282 | "symbol": "IBM", 283 | "date": "Jun 2009", 284 | "price": 103.01 285 | }, 286 | { 287 | "symbol": "IBM", 288 | "date": "Jul 2009", 289 | "price": 116.34 290 | }, 291 | { 292 | "symbol": "IBM", 293 | "date": "Aug 2009", 294 | "price": 117 295 | }, 296 | { 297 | "symbol": "IBM", 298 | "date": "Sep 2009", 299 | "price": 118.55 300 | }, 301 | { 302 | "symbol": "IBM", 303 | "date": "Oct 2009", 304 | "price": 119.54 305 | }, 306 | { 307 | "symbol": "IBM", 308 | "date": "Nov 2009", 309 | "price": 125.79 310 | }, 311 | { 312 | "symbol": "IBM", 313 | "date": "Dec 2009", 314 | "price": 130.32 315 | }, 316 | { 317 | "symbol": "AAPL", 318 | "date": "Apr 2000", 319 | "price": 31.01 320 | }, 321 | { 322 | "symbol": "AAPL", 323 | "date": "May 2000", 324 | "price": 21 325 | }, 326 | { 327 | "symbol": "AAPL", 328 | "date": "Jun 2000", 329 | "price": 26.19 330 | }, 331 | { 332 | "symbol": "AAPL", 333 | "date": "Jul 2000", 334 | "price": 25.41 335 | }, 336 | { 337 | "symbol": "AAPL", 338 | "date": "Aug 2000", 339 | "price": 30.47 340 | }, 341 | { 342 | "symbol": "AAPL", 343 | "date": "Sep 2000", 344 | "price": 12.88 345 | }, 346 | { 347 | "symbol": "AAPL", 348 | "date": "Oct 2000", 349 | "price": 9.78 350 | }, 351 | { 352 | "symbol": "AAPL", 353 | "date": "Nov 2000", 354 | "price": 8.25 355 | }, 356 | { 357 | "symbol": "AAPL", 358 | "date": "Dec 2000", 359 | "price": 7.44 360 | }, 361 | { 362 | "symbol": "AAPL", 363 | "date": "Jan 2001", 364 | "price": 10.81 365 | }, 366 | { 367 | "symbol": "AAPL", 368 | "date": "Feb 2001", 369 | "price": 9.12 370 | }, 371 | { 372 | "symbol": "AAPL", 373 | "date": "Mar 2001", 374 | "price": 11.03 375 | }, 376 | { 377 | "symbol": "AAPL", 378 | "date": "Apr 2001", 379 | "price": 12.74 380 | }, 381 | { 382 | "symbol": "AAPL", 383 | "date": "May 2001", 384 | "price": 9.98 385 | }, 386 | { 387 | "symbol": "AAPL", 388 | "date": "Jun 2001", 389 | "price": 11.62 390 | }, 391 | { 392 | "symbol": "AAPL", 393 | "date": "Feb 2002", 394 | "price": 10.85 395 | }, 396 | { 397 | "symbol": "AAPL", 398 | "date": "Mar 2002", 399 | "price": 11.84 400 | }, 401 | { 402 | "symbol": "AAPL", 403 | "date": "Apr 2002", 404 | "price": 12.14 405 | }, 406 | { 407 | "symbol": "AAPL", 408 | "date": "May 2002", 409 | "price": 11.65 410 | }, 411 | { 412 | "symbol": "AAPL", 413 | "date": "Jun 2002", 414 | "price": 8.86 415 | }, 416 | { 417 | "symbol": "AAPL", 418 | "date": "Jul 2002", 419 | "price": 7.63 420 | }, 421 | { 422 | "symbol": "AAPL", 423 | "date": "Aug 2002", 424 | "price": 7.38 425 | }, 426 | { 427 | "symbol": "AAPL", 428 | "date": "Sep 2002", 429 | "price": 7.25 430 | }, 431 | { 432 | "symbol": "AAPL", 433 | "date": "Oct 2002", 434 | "price": 8.03 435 | }, 436 | { 437 | "symbol": "AAPL", 438 | "date": "Nov 2002", 439 | "price": 7.75 440 | }, 441 | { 442 | "symbol": "AAPL", 443 | "date": "Dec 2002", 444 | "price": 7.16 445 | }, 446 | { 447 | "symbol": "AAPL", 448 | "date": "Jan 2003", 449 | "price": 7.18 450 | }, 451 | { 452 | "symbol": "AAPL", 453 | "date": "Feb 2003", 454 | "price": 7.51 455 | }, 456 | { 457 | "symbol": "AAPL", 458 | "date": "Mar 2003", 459 | "price": 7.07 460 | }, 461 | { 462 | "symbol": "AAPL", 463 | "date": "Apr 2003", 464 | "price": 7.11 465 | }, 466 | { 467 | "symbol": "AAPL", 468 | "date": "May 2003", 469 | "price": 8.98 470 | }, 471 | { 472 | "symbol": "AAPL", 473 | "date": "Jun 2003", 474 | "price": 9.53 475 | }, 476 | { 477 | "symbol": "AAPL", 478 | "date": "Jul 2003", 479 | "price": 10.54 480 | }, 481 | { 482 | "symbol": "AAPL", 483 | "date": "Aug 2003", 484 | "price": 11.31 485 | }, 486 | { 487 | "symbol": "AAPL", 488 | "date": "Sep 2003", 489 | "price": 10.36 490 | }, 491 | { 492 | "symbol": "AAPL", 493 | "date": "Oct 2003", 494 | "price": 11.44 495 | }, 496 | { 497 | "symbol": "AAPL", 498 | "date": "Nov 2003", 499 | "price": 10.45 500 | }, 501 | { 502 | "symbol": "AAPL", 503 | "date": "Dec 2003", 504 | "price": 10.69 505 | }, 506 | { 507 | "symbol": "AAPL", 508 | "date": "Jan 2004", 509 | "price": 11.28 510 | }, 511 | { 512 | "symbol": "AAPL", 513 | "date": "Feb 2004", 514 | "price": 11.96 515 | }, 516 | { 517 | "symbol": "AAPL", 518 | "date": "Mar 2004", 519 | "price": 13.52 520 | }, 521 | { 522 | "symbol": "AAPL", 523 | "date": "Apr 2004", 524 | "price": 12.89 525 | }, 526 | { 527 | "symbol": "AAPL", 528 | "date": "May 2004", 529 | "price": 14.03 530 | }, 531 | { 532 | "symbol": "AAPL", 533 | "date": "Jun 2004", 534 | "price": 16.27 535 | }, 536 | { 537 | "symbol": "AAPL", 538 | "date": "Jul 2004", 539 | "price": 16.17 540 | }, 541 | { 542 | "symbol": "AAPL", 543 | "date": "Aug 2004", 544 | "price": 17.25 545 | }, 546 | { 547 | "symbol": "AAPL", 548 | "date": "Sep 2004", 549 | "price": 19.38 550 | }, 551 | { 552 | "symbol": "AAPL", 553 | "date": "Oct 2004", 554 | "price": 26.2 555 | }, 556 | { 557 | "symbol": "AAPL", 558 | "date": "Nov 2004", 559 | "price": 33.53 560 | }, 561 | { 562 | "symbol": "AAPL", 563 | "date": "Dec 2004", 564 | "price": 32.2 565 | }, 566 | { 567 | "symbol": "AAPL", 568 | "date": "Jan 2005", 569 | "price": 38.45 570 | }, 571 | { 572 | "symbol": "AAPL", 573 | "date": "Feb 2005", 574 | "price": 44.86 575 | }, 576 | { 577 | "symbol": "AAPL", 578 | "date": "Mar 2005", 579 | "price": 41.67 580 | }, 581 | { 582 | "symbol": "AAPL", 583 | "date": "Apr 2005", 584 | "price": 36.06 585 | }, 586 | { 587 | "symbol": "AAPL", 588 | "date": "May 2005", 589 | "price": 39.76 590 | }, 591 | { 592 | "symbol": "AAPL", 593 | "date": "Aug 2006", 594 | "price": 67.85 595 | }, 596 | { 597 | "symbol": "AAPL", 598 | "date": "Sep 2006", 599 | "price": 76.98 600 | }, 601 | { 602 | "symbol": "AAPL", 603 | "date": "Oct 2006", 604 | "price": 81.08 605 | }, 606 | { 607 | "symbol": "AAPL", 608 | "date": "Nov 2006", 609 | "price": 91.66 610 | }, 611 | { 612 | "symbol": "AAPL", 613 | "date": "Dec 2006", 614 | "price": 84.84 615 | }, 616 | { 617 | "symbol": "AAPL", 618 | "date": "Jan 2007", 619 | "price": 85.73 620 | }, 621 | { 622 | "symbol": "AAPL", 623 | "date": "Feb 2007", 624 | "price": 84.61 625 | }, 626 | { 627 | "symbol": "AAPL", 628 | "date": "Mar 2007", 629 | "price": 92.91 630 | }, 631 | { 632 | "symbol": "AAPL", 633 | "date": "Apr 2007", 634 | "price": 99.8 635 | }, 636 | { 637 | "symbol": "AAPL", 638 | "date": "May 2007", 639 | "price": 121.19 640 | }, 641 | { 642 | "symbol": "AAPL", 643 | "date": "Jun 2007", 644 | "price": 122.04 645 | }, 646 | { 647 | "symbol": "AAPL", 648 | "date": "Jul 2007", 649 | "price": 131.76 650 | }, 651 | { 652 | "symbol": "AAPL", 653 | "date": "Aug 2007", 654 | "price": 138.48 655 | }, 656 | { 657 | "symbol": "AAPL", 658 | "date": "Sep 2007", 659 | "price": 153.47 660 | }, 661 | { 662 | "symbol": "AAPL", 663 | "date": "Oct 2007", 664 | "price": 189.95 665 | }, 666 | { 667 | "symbol": "AAPL", 668 | "date": "Nov 2007", 669 | "price": 182.22 670 | }, 671 | { 672 | "symbol": "AAPL", 673 | "date": "Dec 2007", 674 | "price": 198.08 675 | }, 676 | { 677 | "symbol": "AAPL", 678 | "date": "Jan 2008", 679 | "price": 135.36 680 | }, 681 | { 682 | "symbol": "AAPL", 683 | "date": "Feb 2008", 684 | "price": 125.02 685 | }, 686 | { 687 | "symbol": "AAPL", 688 | "date": "Mar 2008", 689 | "price": 143.5 690 | }, 691 | { 692 | "symbol": "AAPL", 693 | "date": "Apr 2008", 694 | "price": 173.95 695 | }, 696 | ]; 697 | 698 | export default dataSample; --------------------------------------------------------------------------------