5 |
6 |
7 |
361 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016 Pooya Parsa
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # JSON to Excel for VUE 2
2 |
3 | Download your JSON data as an Excel file directly from the browser. This component is based on the solution proposed on [this thread](https://stackoverflow.com/questions/17142427/javascript-to-export-html-table-to-excel)
4 |
5 | ### Important! Extra prompt in Microsoft Excel
6 |
7 | **The method implemented in this component uses HTML tables to draw the .xls files, Microsoft Excel no longer recognize HTML as native content so a warning message will be displayed before opening the file. The content will be rendered perfectly but the message can't be avoided.**
8 |
9 | ## Getting started
10 |
11 | Get the package:
12 |
13 | ```bash
14 | npm install vue-json-excel
15 | ```
16 |
17 | Register JsonExcel in your vue app entry point:
18 |
19 | ```js
20 | import Vue from "vue";
21 | import JsonExcel from "vue-json-excel";
22 |
23 | Vue.component("downloadExcel", JsonExcel);
24 | ```
25 |
26 | In your template
27 |
28 | ```html
29 |
30 | Download Data
31 |
32 |
33 | ```
34 |
35 | ## Props List
36 |
37 | | Name | Type | Description | Default |
38 | | :--------------------------- | :----------: | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------: |
39 | | data | Array | Data to be exported. |
40 | | fields | Object | Fields inside the JSON Object that you want to export. If none provided, all properties in the JSON will be exported. |
41 | | export-fields (exportFields) | Object | Used to fix the problem with other components that use the variable fields, like vee-validate. exportFields works exactly like fields |
42 | | type | string | Mime type [xls, csv] | xls |
43 | | name | string | File name to export. | data.xls |
44 | | header | string/Array | Title(s) for the data. Can be a string (one title) or an array of strings (multiple titles). |
45 | | title(deprecated) | string/Array | same as header, title is maintained for retro-compatibility purposes but its use is not recommended due to the conflict with the HTML5 title attribute. |
46 | | footer | string/Array | Footer(s) for the data. Can be a string (one footer) or an array of strings (multiple footers). |
47 | | default-value (defaultValue) | string | Use as fallback when the row has no field values. | '' |
48 | | worksheet | string | Name of the worksheet tab. | 'Sheet1' |
49 | | fetch | Function | Callback to fetch data before download, if it's set it runs immediately after mouse pressed and before download process. IMPORTANT: only works if no data prop is defined. |
50 | | before-generate | Function | Callback to call a method right before the generate / fetch data, eg:show loading progress |
51 | | before-finish | Function | Callback to call a method right before the download box pops out, eg:hide loading progress |
52 | | stringifyLongNum | Boolean | stringify long number and decimal(solve the problem of loss of digital accuracy), default: false |
53 | | escapeCsv | Boolean | This escapes CSV values in order to fix some excel problems with number fields. But this will wrap every csv data with **="** and **"**, to avoid that you have to set this prop to false. default: True |
54 |
55 | ## Example
56 |
57 | ```js
58 | import Vue from "vue";
59 | import JsonExcel from "vue-json-excel";
60 |
61 | Vue.component("downloadExcel", JsonExcel);
62 |
63 | const app = new Vue({
64 | el: "#app",
65 | data: {
66 | json_fields: {
67 | "Complete name": "name",
68 | City: "city",
69 | Telephone: "phone.mobile",
70 | "Telephone 2": {
71 | field: "phone.landline",
72 | callback: (value) => {
73 | return `Landline Phone - ${value}`;
74 | },
75 | },
76 | },
77 | json_data: [
78 | {
79 | name: "Tony Peña",
80 | city: "New York",
81 | country: "United States",
82 | birthdate: "1978-03-15",
83 | phone: {
84 | mobile: "1-541-754-3010",
85 | landline: "(541) 754-3010",
86 | },
87 | },
88 | {
89 | name: "Thessaloniki",
90 | city: "Athens",
91 | country: "Greece",
92 | birthdate: "1987-11-23",
93 | phone: {
94 | mobile: "+1 855 275 5071",
95 | landline: "(2741) 2621-244",
96 | },
97 | },
98 | ],
99 | json_meta: [
100 | [
101 | {
102 | key: "charset",
103 | value: "utf-8",
104 | },
105 | ],
106 | ],
107 | },
108 | });
109 | ```
110 |
111 | In your HTML call it like
112 |
113 | ```html
114 |
121 | Download Excel (you can customize this with html code!)
122 |
123 | ```
124 |
125 | REQUIRED
126 |
127 | - json_data: Contains the data you want to export.
128 | - json_fields: You can select what fields to export. Specify nested data and assign labels to the fields. The key is the label, the value is the JSON field. This will export the field data 'as is'. If you need to customize the the exported data you can define a callback function. Thanks to @gucastiliao.
129 |
130 | ```js
131 | let json_fields = {
132 | // regular field (exported data 'as is')
133 | fieldLabel: attributeName, // nested attribute supported
134 | // callback function for data formatting
135 | anotherFieldLabel: {
136 | field: anotherAttributeName, // nested attribute supported
137 | callback: (value) => {
138 | return `formatted value ${value}`;
139 | },
140 | },
141 | };
142 | ```
143 |
144 | json_fields is a object that represents which columns will be exported. If no object is provided, the component will be use the first object in your data array to extract the keys as columns names. Json field example:
145 |
146 | ```
147 | :export-fields="{
148 | 'Human friendly name': '_name_field_from_json',
149 | 'user's last name': '_last_name_text'
150 | }"
151 | ```
152 |
153 | ## Export CSV
154 |
155 | To export JSON as a CSV file, just add the prop `type` with a value of "csv":
156 |
157 | ```html
158 |
165 | Download CSV (you can customize this with html code!)
166 |
167 | ```
168 |
169 | ## Multi-line values will appear in a single cell
170 |
171 | A single text value in the data that contains newline characters will appear as a single cell in Excel. This avoids the undesired behavior of multi-line values getting split into multiple cells that must be merged before using data filters and pivot tables.
172 |
173 | For example:
174 |
175 | ```html
176 |
177 |
178 |
179 |
180 |
181 |
204 | ```
205 |
206 | 
207 |
208 | ## Fetch Data on Demand
209 |
210 | In case you need to fetch data from the server, you could use the fetch prop that allows you to define a callback function that is executed when your user click the download button. This function has to return a JSON value containing the data to export. A basic use case is:
211 |
212 | ```js
213 |
214 |
215 |
216 |
217 |
Fetch Example
218 |
224 | Download Excel
225 |
226 |
227 |
228 |
229 |
261 |
262 | ```
263 |
264 | ## Using callbacks
265 |
266 | when using callback functions in the fields description, you have three option to retrieve data:
267 |
268 | - **field: 'path.to.nested.property'** you can retrieve a specific value using the nested property notation.
269 |
270 | ```js
271 | json_fields: {
272 | 'Complete name': 'name',
273 | 'City': 'city',
274 | 'Telephone': 'phone.mobile',
275 | 'Telephone 2' : {
276 | field: 'phone.landline',
277 | callback: (value) => {
278 | return `Landline Phone - ${value}`;
279 | }
280 | },
281 | },
282 | ```
283 |
284 | - **field: 'define.nested.object'** you can retrieve a nested object too.
285 |
286 | ```js
287 | json_fields: {s
288 | 'Complete name': 'name',
289 | 'City': 'city',
290 | 'Telephone': 'phone.mobile',
291 | 'Telephone 2' : {
292 | field: 'phone',
293 | callback: (value) => {
294 | return `Landline Phone - ${value.landline}`;
295 | }
296 | },
297 | },
298 | ```
299 |
300 | - Or **get the whole row** if field is undefined.
301 |
302 | ```js
303 | json_fields: {
304 | 'Complete name': 'name',
305 | 'City': 'city',
306 | 'Telephone': 'phone.mobile',
307 | 'Telephone 2' : {
308 | callback: (value) => {
309 | return `Landline Phone - ${value.phone.landline}`;
310 | }
311 | },
312 | },
313 | ```
314 |
315 | ## License
316 |
317 | MIT
318 |
319 | #### Status
320 |
321 | This project is in an early stage of development. Any contribution is welcome :D
322 |
--------------------------------------------------------------------------------
/dist/vue-json-excel.cjs.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
4 |
5 | function createCommonjsModule(fn, module) {
6 | return module = { exports: {} }, fn(module, module.exports), module.exports;
7 | }
8 |
9 | var download = createCommonjsModule(function (module, exports) {
10 | //download.js v4.2, by dandavis; 2008-2016. [MIT] see http://danml.com/download.html for tests/usage
11 | // v1 landed a FF+Chrome compat way of downloading strings to local un-named files, upgraded to use a hidden frame and optional mime
12 | // v2 added named files via a[download], msSaveBlob, IE (10+) support, and window.URL support for larger+faster saves than dataURLs
13 | // v3 added dataURL and Blob Input, bind-toggle arity, and legacy dataURL fallback was improved with force-download mime and base64 support. 3.1 improved safari handling.
14 | // v4 adds AMD/UMD, commonJS, and plain browser support
15 | // v4.1 adds url download capability via solo URL argument (same domain/CORS only)
16 | // v4.2 adds semantic variable names, long (over 2MB) dataURL support, and hidden by default temp anchors
17 | // https://github.com/rndme/download
18 |
19 | (function (root, factory) {
20 | {
21 | // Node. Does not work with strict CommonJS, but
22 | // only CommonJS-like environments that support module.exports,
23 | // like Node.
24 | module.exports = factory();
25 | }
26 | }(commonjsGlobal, function () {
27 |
28 | return function download(data, strFileName, strMimeType) {
29 |
30 | var self = window, // this script is only for browsers anyway...
31 | defaultMime = "application/octet-stream", // this default mime also triggers iframe downloads
32 | mimeType = strMimeType || defaultMime,
33 | payload = data,
34 | url = !strFileName && !strMimeType && payload,
35 | anchor = document.createElement("a"),
36 | toString = function(a){return String(a);},
37 | myBlob = (self.Blob || self.MozBlob || self.WebKitBlob || toString),
38 | fileName = strFileName || "download",
39 | blob,
40 | reader;
41 | myBlob= myBlob.call ? myBlob.bind(self) : Blob ;
42 |
43 | if(String(this)==="true"){ //reverse arguments, allowing download.bind(true, "text/xml", "export.xml") to act as a callback
44 | payload=[payload, mimeType];
45 | mimeType=payload[0];
46 | payload=payload[1];
47 | }
48 |
49 |
50 | if(url && url.length< 2048){ // if no filename and no mime, assume a url was passed as the only argument
51 | fileName = url.split("/").pop().split("?")[0];
52 | anchor.href = url; // assign href prop to temp anchor
53 | if(anchor.href.indexOf(url) !== -1){ // if the browser determines that it's a potentially valid url path:
54 | var ajax=new XMLHttpRequest();
55 | ajax.open( "GET", url, true);
56 | ajax.responseType = 'blob';
57 | ajax.onload= function(e){
58 | download(e.target.response, fileName, defaultMime);
59 | };
60 | setTimeout(function(){ ajax.send();}, 0); // allows setting custom ajax headers using the return:
61 | return ajax;
62 | } // end if valid url?
63 | } // end if url?
64 |
65 |
66 | //go ahead and download dataURLs right away
67 | if(/^data:([\w+-]+\/[\w+.-]+)?[,;]/.test(payload)){
68 |
69 | if(payload.length > (1024*1024*1.999) && myBlob !== toString ){
70 | payload=dataUrlToBlob(payload);
71 | mimeType=payload.type || defaultMime;
72 | }else {
73 | return navigator.msSaveBlob ? // IE10 can't do a[download], only Blobs:
74 | navigator.msSaveBlob(dataUrlToBlob(payload), fileName) :
75 | saver(payload) ; // everyone else can save dataURLs un-processed
76 | }
77 |
78 | }else {//not data url, is it a string with special needs?
79 | if(/([\x80-\xff])/.test(payload)){
80 | var i=0, tempUiArr= new Uint8Array(payload.length), mx=tempUiArr.length;
81 | for(i;i null,
193 | },
194 | // this prop is used to fix the problem with other components that use the
195 | // variable fields, like vee-validate. exportFields works exactly like fields
196 | exportFields: {
197 | type: Object,
198 | default: () => null,
199 | },
200 | // Use as fallback when the row has no field values
201 | defaultValue: {
202 | type: String,
203 | required: false,
204 | default: "",
205 | },
206 | // Title(s) for the data, could be a string or an array of strings (multiple titles)
207 | header: {
208 | default: null,
209 | },
210 | // Footer(s) for the data, could be a string or an array of strings (multiple footers)
211 | footer: {
212 | default: null,
213 | },
214 | // filename to export
215 | name: {
216 | type: String,
217 | default: "data.xls",
218 | },
219 | fetch: {
220 | type: Function,
221 | },
222 | meta: {
223 | type: Array,
224 | default: () => [],
225 | },
226 | worksheet: {
227 | type: String,
228 | default: "Sheet1",
229 | },
230 | //event before generate was called
231 | beforeGenerate: {
232 | type: Function,
233 | },
234 | //event before download pops up
235 | beforeFinish: {
236 | type: Function,
237 | },
238 | // Determine if CSV Data should be escaped
239 | escapeCsv: {
240 | type: Boolean,
241 | default: true,
242 | },
243 | // long number stringify
244 | stringifyLongNum: {
245 | type: Boolean,
246 | default: false,
247 | },
248 | },
249 | computed: {
250 | // unique identifier
251 | idName() {
252 | var now = new Date().getTime();
253 | return "export_" + now;
254 | },
255 |
256 | downloadFields() {
257 | if (this.fields) return this.fields;
258 |
259 | if (this.exportFields) return this.exportFields;
260 | },
261 | },
262 | methods: {
263 | async generate() {
264 | if (typeof this.beforeGenerate === "function") {
265 | await this.beforeGenerate();
266 | }
267 | let data = this.data;
268 | if (typeof this.fetch === "function" || !data) data = await this.fetch();
269 |
270 | if (!data || !data.length) {
271 | return;
272 | }
273 |
274 | let json = this.getProcessedJson(data, this.downloadFields);
275 | if (this.type === "html") {
276 | // this is mainly for testing
277 | return this.export(
278 | this.jsonToXLS(json),
279 | this.name.replace(".xls", ".html"),
280 | "text/html"
281 | );
282 | } else if (this.type === "csv") {
283 | return this.export(
284 | this.jsonToCSV(json),
285 | this.name.replace(".xls", ".csv"),
286 | "application/csv"
287 | );
288 | }
289 | return this.export(
290 | this.jsonToXLS(json),
291 | this.name,
292 | "application/vnd.ms-excel"
293 | );
294 | },
295 | /*
296 | Use downloadjs to generate the download link
297 | */
298 | export: async function (data, filename, mime) {
299 | let blob = this.base64ToBlob(data, mime);
300 | if (typeof this.beforeFinish === "function") await this.beforeFinish();
301 | download(blob, filename, mime);
302 | },
303 | /*
304 | jsonToXLS
305 | ---------------
306 | Transform json data into an xml document with MS Excel format, sadly
307 | it shows a prompt when it opens, that is a default behavior for
308 | Microsoft office and cannot be avoided. It's recommended to use CSV format instead.
309 | */
310 | jsonToXLS(data) {
311 | let xlsTemp =
312 | '