Skip to content

Commit f613600

Browse files
authored
Merge pull request #678 from jmaister/column-types
Allow to define the cell types and formats.
2 parents 193c848 + 41eff6b commit f613600

11 files changed

+360
-36
lines changed

.github/workflows/webpack.yml

+5-2
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,15 @@ jobs:
1616
node-version: [18.x]
1717

1818
steps:
19-
- uses: actions/checkout@v2
19+
- uses: actions/checkout@v3
20+
with:
21+
fetch-depth: 0
2022

2123
- name: Use Node.js ${{ matrix.node-version }}
22-
uses: actions/setup-node@v1
24+
uses: actions/setup-node@v3
2325
with:
2426
node-version: ${{ matrix.node-version }}
27+
cache: 'yarn'
2528

2629
- run: yarn install
2730

README.md

+46-2
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,17 @@
1414

1515
- As part of the new version 3.0.0+, there is support for _XLSX_. The drawback is that the library is 200+ KB.
1616

17-
- If you only need _XLS_ or _CSV_, use _2.X.X_ versions.
18-
1917
- Check My Blog Page for Testing :
2018
[JavaScript export to Excel](http://jordiburgos.com/post/2013/javascript-export-to-excel.html)
2119

2220
[ExcellentExport.js update: JavaScript export to Excel and CSV](http://jordiburgos.com/post/2017/excellentexport-javascript-export-to-excel-csv.html)
2321

2422
# Revision history:
2523

24+
### 3.9.0
25+
26+
* Cell types and formats!!! Now you can define the cell type and format. For example, you can define a cell as a date or a number. You can also define the format of the cell. For example, you can define a cell as a date with the format "dd/mm/yyyy" or a number with the format "#,##0.00".
27+
2628
### 3.8.1
2729

2830
* Activate XLSX compression by default. The example of index.bigtable.html went from 18Mb to 3Mb.
@@ -241,6 +243,7 @@
241243
fixValue: function(value, row, column) {return fixedValue} // Function to fix values, receiving value, row num, column num
242244
fixArray: function(array) {return array} // Function to manipulate the whole data array
243245
rtl: Use Right-to-left characters, boolean (optional)
246+
formats: [...] // Array of formats for each column. See formats below.
244247
...
245248
},
246249
{
@@ -259,6 +262,47 @@ It transforms BR to line breaks and then strips all the HTML tags.
259262
return strippedString;
260263
}
261264

265+
## Formats
266+
267+
You can specify an array with the formats for a specific cell range (i.e. A1:A100, A1:D100, A1:H1, etc).
268+
269+
Each element in the format array consists on:
270+
271+
```json
272+
{
273+
"range": "A1:A100", // Range of cells to apply the format, mandatory
274+
"format": {
275+
"type": "<cell_type>", // Type of format, mandatory
276+
"pattern": "<pattern>" // Pattern, optional
277+
}
278+
}
279+
```
280+
281+
`format` can be used from one of the predefined types if you use TypeScript
282+
283+
```typescript
284+
{
285+
"range": "A1:A100",
286+
"format": PredefinedFormat.INTEGER
287+
}
288+
```
289+
290+
`cell_type` can be one of the followint:
291+
292+
's': String
293+
'n': Number
294+
'd': Date
295+
'b': Boolean
296+
297+
`pattern` is a string with the format pattern used in Excel. For example:
298+
299+
'0' // Integer
300+
'0.00' // 2 decimals
301+
'dd/mm/yyyy' // Date
302+
'dd/mm/yyyy hh:mm:ss' // Date and time
303+
'0.00%' // Percentage
304+
'0.00e+00' // Scientific notation
305+
'@' // Text
262306

263307
# Notes
264308

dist/excellentexport.d.ts

+3
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
* @url: https://github.com/jmaister/excellentexport
77
*
88
*/
9+
import { FormatDefinition } from './format';
910
declare global {
1011
interface Navigator {
1112
msSaveBlob?: (blob: any, defaultName?: string) => boolean;
@@ -30,9 +31,11 @@ export interface SheetOptions {
3031
fixValue?(value: any, row: number, column: number): any;
3132
fixArray?(array: any[][]): any[][];
3233
rtl?: boolean;
34+
formats?: (FormatDefinition | null)[];
3335
}
3436
declare const ExcellentExport: {
3537
version: () => string;
38+
formats: import("./format").CellFormats;
3639
excel: (anchor: (HTMLAnchorElement | string), table: HTMLTableElement, name: string) => boolean;
3740
csv: (anchor: (HTMLAnchorElement | string), table: HTMLTableElement, delimiter?: string, newLine?: string) => boolean;
3841
convert: (options: ConvertOptions, sheets: SheetOptions[]) => string | false;

dist/excellentexport.js

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/format.d.ts

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
export declare enum CellType {
2+
TEXT = "s",
3+
NUMBER = "n",
4+
DATE = "d",
5+
BOOLEAN = "b"
6+
}
7+
export declare enum CellPattern {
8+
INTEGER = "0",
9+
DECIMAL = "0.00",
10+
DATE = "dd/mm/yyyy",
11+
TIME = "hh:mm:ss",
12+
DATETIME = "dd/mm/yyyy hh:mm:ss",
13+
CURRENCY = "[$$-409]#,##0.00;[RED]-[$$-409]#,##0.00",
14+
PERCENTAGE = "0.00%",
15+
EXPONENT = "0.00E+00",
16+
TEXT = "@"
17+
}
18+
export interface CellFormat {
19+
type: CellType;
20+
pattern?: CellPattern;
21+
}
22+
export interface CellFormats {
23+
[key: string]: CellFormat;
24+
}
25+
export declare const PredefinedFormat: CellFormats;
26+
export interface FormatDefinition {
27+
range: string;
28+
format?: CellFormat;
29+
}

dist/utils.d.ts

+30-29
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,30 @@
1-
export declare const b64toBlob: (b64Data: string, contentType: string, sliceSize?: number) => Blob;
2-
export declare const templates: {
3-
excel: string;
4-
};
5-
/**
6-
* Convert a string to Base64.
7-
*/
8-
export declare const base64: (s: string) => string;
9-
export declare const format: (s: string, context: any) => string;
10-
/**
11-
* Get element by ID.
12-
* @param {*} element
13-
*/
14-
export declare const getTable: (element: (HTMLTableElement | string)) => HTMLTableElement;
15-
/**
16-
* Get element by ID.
17-
* @param {*} element
18-
*/
19-
export declare const getAnchor: (element: (HTMLAnchorElement | string)) => HTMLAnchorElement;
20-
/**
21-
* Encode a value for CSV.
22-
* @param {*} value
23-
*/
24-
export declare const fixCSVField: (value: string, csvDelimiter: string) => string;
25-
export declare const tableToArray: (table: HTMLTableElement) => any[][];
26-
export declare const tableToCSV: (table: HTMLTableElement, csvDelimiter?: string, csvNewLine?: string) => string;
27-
export declare const createDownloadLink: (anchor: HTMLAnchorElement, base64data: string, exporttype: string, filename: string) => boolean;
28-
export declare const string2ArrayBuffer: (s: string) => ArrayBuffer;
29-
export declare const removeColumns: (dataArray: any[][], columnIndexes: number[]) => void;
1+
export declare const b64toBlob: (b64Data: string, contentType: string, sliceSize?: number) => Blob;
2+
export declare const templates: {
3+
excel: string;
4+
};
5+
/**
6+
* Convert a string to Base64.
7+
*/
8+
export declare const base64: (s: string) => string;
9+
export declare const format: (s: string, context: any) => string;
10+
/**
11+
* Get element by ID.
12+
* @param {*} element
13+
*/
14+
export declare const getTable: (element: (HTMLTableElement | string)) => HTMLTableElement;
15+
/**
16+
* Get element by ID.
17+
* @param {*} element
18+
*/
19+
export declare const getAnchor: (element: (HTMLAnchorElement | string)) => HTMLAnchorElement;
20+
/**
21+
* Encode a value for CSV.
22+
* @param {*} value
23+
*/
24+
export declare const fixCSVField: (value: string, csvDelimiter: string) => string;
25+
export declare const tableToArray: (table: HTMLTableElement) => any[][];
26+
export declare const tableToCSV: (table: HTMLTableElement, csvDelimiter?: string, csvNewLine?: string) => string;
27+
export declare const createDownloadLink: (anchor: HTMLAnchorElement, base64data: string, exporttype: string, filename: string) => boolean;
28+
export declare const string2ArrayBuffer: (s: string) => ArrayBuffer;
29+
export declare const removeColumns: (dataArray: any[][], columnIndexes: number[]) => void;
30+
export declare const hasContent: (value: any) => boolean;

index.format.html

+100
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<meta charset="utf-8">
5+
<title>Export to excel test</title>
6+
<script src="dist/excellentexport.js"></script>
7+
<style>
8+
table, tr, td {
9+
border: 1px black solid;
10+
}
11+
</style>
12+
<script>
13+
function newApi(format) {
14+
return ExcellentExport.convert({
15+
anchor: 'anchorNewApi-' + format,
16+
filename: 'data',
17+
format: format
18+
}, [{
19+
name: 'Formatted Sheet',
20+
from: {
21+
table: 'datatable'
22+
},
23+
formats: [
24+
{ range: "A2:A10", format: ExcellentExport.formats.INTEGER },
25+
{ range: "B2:B10", format: ExcellentExport.formats.TEXT },
26+
{ range: "C2:C10", format: ExcellentExport.formats.DATE },
27+
{ range: "D2:D10", format: ExcellentExport.formats.DECIMAL },
28+
{ range: "E2:E10", format: ExcellentExport.formats.BOOLEAN },
29+
{ range: "F2:F10", format: ExcellentExport.formats.INTEGER },
30+
{ range: "A5:E5", format: ExcellentExport.formats.TEXT },
31+
{ range: "A6", format: ExcellentExport.formats.DECIMAL },
32+
],
33+
}]);
34+
}
35+
</script>
36+
</head>
37+
<body>
38+
<h1>ExcellentExport.js</h1>
39+
40+
<h3>Test page</h3>
41+
42+
Test table:
43+
<table id="datatable">
44+
<tr>
45+
<th>ID</th>
46+
<th>Name</th>
47+
<th>Birthdate</th>
48+
<th>Salary</th>
49+
<th>Active</th>
50+
<th>Big number</th>
51+
</tr>
52+
<tr>
53+
<td>1</td>
54+
<td>John</td>
55+
<td>1980-12-10</td>
56+
<td>98762000.55</td>
57+
<td>1</td>
58+
<td>987654321987654</td>
59+
</tr>
60+
<tr>
61+
<td>2</td>
62+
<td>Peter</td>
63+
<td>1978-01-23</td>
64+
<td>98762500.43</td>
65+
<td>0</td>
66+
<td>876543219987654</td>
67+
</tr>
68+
<tr>
69+
<td>3</td>
70+
<td>George</td>
71+
<td>1985-11-30</td>
72+
<td>98761800.98</td>
73+
<td>1</td>
74+
<td>765432198987654</td>
75+
</tr>
76+
<tr>
77+
<td>End</td>
78+
<td>End</td>
79+
<td>End</td>
80+
<td>End</td>
81+
<td>End</td>
82+
<td>End</td>
83+
</tr>
84+
<tr>
85+
<td>9876543.21</td>
86+
<td></td>
87+
<td></td>
88+
<td></td>
89+
<td></td>
90+
<td></td>
91+
</tr>
92+
</table>
93+
94+
<br/>
95+
96+
<a href="#" id="anchorNewApi-xlsx" onclick="return newApi('xlsx');">Export Excel</a>
97+
<a href="#" id="anchorNewApi-csv" onclick="return newApi('csv');">Export CSV</a>
98+
99+
</body>
100+
</html>

src/excellentexport.ts

+34-2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
*/
99

1010
import * as XLSX from 'xlsx';
11+
import { CellType, FormatDefinition, PredefinedFormat } from './format';
1112

1213
import * as utils from './utils';
1314

@@ -29,17 +30,18 @@ export interface FromOptions {
2930
table?: (string|HTMLTableElement),
3031
array?: any[][],
3132
}
33+
3234
export interface SheetOptions {
3335
name: string,
3436
from: FromOptions,
3537
removeColumns?: number[],
3638
filterRowFn?(row:any[]): boolean ,
3739
fixValue?(value:any, row:number, column:number): any,
3840
fixArray?(array:any[][]): any[][],
39-
rtl?: boolean
41+
rtl?: boolean,
42+
formats?: (FormatDefinition | null)[],
4043
}
4144

42-
4345
const ExcellentExport = function() {
4446

4547
const version = "3.8.1";
@@ -138,6 +140,35 @@ const ExcellentExport = function() {
138140
// Create sheet
139141
workbook.SheetNames.push(name);
140142
const worksheet = XLSX.utils.aoa_to_sheet(dataArray, {sheet: name} as XLSX.AOA2SheetOpts);
143+
144+
// Apply format
145+
if (sheetConf.formats) {
146+
sheetConf.formats.forEach(f => {
147+
const range = XLSX.utils.decode_range(f.range);
148+
for (let R = range.s.r; R <= range.e.r; ++R) {
149+
for (let C = range.s.c; C <= range.e.c; ++C) {
150+
const cell = worksheet[XLSX.utils.encode_cell({r: R, c: C})];
151+
if (cell && utils.hasContent(cell.v)) {
152+
// type
153+
cell.t = f.format.type;
154+
155+
// type fix
156+
if (f.format?.type == CellType.BOOLEAN) {
157+
const v = cell.v.toString().toLowerCase();
158+
if (v == 'true' || v == '1') cell.v = true;
159+
if (v == 'false' || v == '0') cell.v = false;
160+
}
161+
// pattern
162+
if (f.format?.pattern) {
163+
cell.z = f.format.pattern;
164+
}
165+
}
166+
}
167+
}
168+
});
169+
}
170+
171+
141172
workbook.Sheets[name] = worksheet;
142173
workbook.Views.push({RTL: options.rtl || sheetConf.rtl || false});
143174
});
@@ -177,6 +208,7 @@ const ExcellentExport = function() {
177208
version: function(): string {
178209
return version;
179210
},
211+
formats: PredefinedFormat,
180212
excel: function(anchor:(HTMLAnchorElement|string), table:HTMLTableElement, name:string) {
181213
table = utils.getTable(table);
182214
anchor = utils.getAnchor(anchor);

0 commit comments

Comments
 (0)