Skip to content

Commit 00989ab

Browse files
committed
fix(exports): grid with colspan should be export accordingly
- read each item metadata to evaluate if the row has any colspan defined and if so then export them accordingly (in Excel we would merge the cells but in regular text export then we would just return empty string)
1 parent 0d858cd commit 00989ab

File tree

6 files changed

+232
-134
lines changed

6 files changed

+232
-134
lines changed

src/app/modules/angular-slickgrid/services/__tests__/excelExport.service.spec.ts

+15-13
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ import { GroupTotalFormatters } from '../..';
2020
// URL object is not supported in JSDOM, we can simply mock it
2121
(global as any).URL.createObjectURL = jest.fn();
2222

23-
const myBoldHtmlFormatter: Formatter = (row, cell, value, columnDef, dataContext) => value !== null ? { text: `<b>${value}</b>` } : null;
24-
const myUppercaseFormatter: Formatter = (row, cell, value, columnDef, dataContext) => value ? { text: value.toUpperCase() } : null;
23+
const myBoldHtmlFormatter: Formatter = (row, cell, value) => value !== null ? { text: `<b>${value}</b>` } : '';
24+
const myUppercaseFormatter: Formatter = (row, cell, value) => value ? { text: value.toUpperCase() } : '';
2525
const myUppercaseGroupTotalFormatter: GroupTotalsFormatter = (totals: any, columnDef: Column) => {
2626
const field = columnDef.field || '';
2727
const val = totals.sum && totals.sum[field];
@@ -44,6 +44,7 @@ const myCustomObjectFormatter: Formatter = (row: number, cell: number, value: an
4444
const dataViewStub = {
4545
getGrouping: jest.fn(),
4646
getItem: jest.fn(),
47+
getItemMetadata: jest.fn(),
4748
getLength: jest.fn(),
4849
setGrouping: jest.fn(),
4950
};
@@ -58,6 +59,7 @@ const gridStub = {
5859
getColumnIndex: jest.fn(),
5960
getOptions: () => mockGridOptions,
6061
getColumns: jest.fn(),
62+
getData: () => dataViewStub,
6163
getGrouping: jest.fn(),
6264
};
6365

@@ -72,7 +74,7 @@ describe('ExcelExportService', () => {
7274
beforeEach(() => {
7375
// @ts-ignore
7476
navigator.__defineGetter__('appName', () => 'Netscape');
75-
navigator.msSaveOrOpenBlob = undefined;
77+
navigator.msSaveOrOpenBlob = undefined as any;
7678
mockExcelBlob = new Blob(['', ''], { type: `text/xlsx;charset=utf-8;` });
7779

7880
mockExportExcelOptions = {
@@ -696,10 +698,10 @@ describe('ExcelExportService', () => {
696698
aggregateEmpty: false,
697699
aggregators: [{ _count: 2, _field: 'order', _nonNullCount: 2, _sum: 4, }],
698700
collapsed: false,
699-
comparer: (a, b) => Sorters.numeric(a.value, b.value, SortDirectionNumber.asc),
701+
comparer: (a: any, b: any) => Sorters.numeric(a.value, b.value, SortDirectionNumber.asc),
700702
compiledAccumulators: [jest.fn(), jest.fn()],
701703
displayTotalsRow: true,
702-
formatter: (g) => `Order: ${g.value} <span style="color:green">(${g.count} items)</span>`,
704+
formatter: (g: any) => `Order: ${g.value} <span style="color:green">(${g.count} items)</span>`,
703705
getter: 'order',
704706
getterIsAFn: false,
705707
lazyTotalsCalculation: true,
@@ -790,10 +792,10 @@ describe('ExcelExportService', () => {
790792
aggregateEmpty: false,
791793
aggregators: [{ _count: 2, _field: 'order', _nonNullCount: 2, _sum: 4, }],
792794
collapsed: false,
793-
comparer: (a, b) => Sorters.numeric(a.value, b.value, SortDirectionNumber.asc),
795+
comparer: (a: any, b: any) => Sorters.numeric(a.value, b.value, SortDirectionNumber.asc),
794796
compiledAccumulators: [jest.fn(), jest.fn()],
795797
displayTotalsRow: true,
796-
formatter: (g) => `Order: ${g.value} <span style="color:green">(${g.count} items)</span>`,
798+
formatter: (g: any) => `Order: ${g.value} <span style="color:green">(${g.count} items)</span>`,
797799
getter: 'order',
798800
getterIsAFn: false,
799801
lazyTotalsCalculation: true,
@@ -888,10 +890,10 @@ describe('ExcelExportService', () => {
888890
aggregateEmpty: false,
889891
aggregators: [{ _count: 2, _field: 'order', _nonNullCount: 2, _sum: 4, }],
890892
collapsed: false,
891-
comparer: (a, b) => Sorters.numeric(a.value, b.value, SortDirectionNumber.asc),
893+
comparer: (a: any, b: any) => Sorters.numeric(a.value, b.value, SortDirectionNumber.asc),
892894
compiledAccumulators: [jest.fn(), jest.fn()],
893895
displayTotalsRow: true,
894-
formatter: (g) => `Order: ${g.value} <span style="color:green">(${g.count} items)</span>`,
896+
formatter: (g: any) => `Order: ${g.value} <span style="color:green">(${g.count} items)</span>`,
895897
getter: 'order',
896898
getterIsAFn: false,
897899
lazyTotalsCalculation: true,
@@ -904,10 +906,10 @@ describe('ExcelExportService', () => {
904906
aggregateEmpty: false,
905907
aggregators: [{ _count: 1, _field: 'lastName', _nonNullCount: 2, _sum: 4, }],
906908
collapsed: false,
907-
comparer: (a, b) => Sorters.numeric(a.value, b.value, SortDirectionNumber.asc),
909+
comparer: (a: any, b: any) => Sorters.numeric(a.value, b.value, SortDirectionNumber.asc),
908910
compiledAccumulators: [jest.fn(), jest.fn()],
909911
displayTotalsRow: true,
910-
formatter: (g) => `Last Name: ${g.value} <span style="color:green">(${g.count} items)</span>`,
912+
formatter: (g: any) => `Last Name: ${g.value} <span style="color:green">(${g.count} items)</span>`,
911913
getter: 'lastName',
912914
getterIsAFn: false,
913915
lazyTotalsCalculation: true,
@@ -998,7 +1000,7 @@ describe('ExcelExportService', () => {
9981000
it(`should have a xlsx export with grouping but without indentation when "addGroupIndentation" is set to False
9991001
and field should be exported as metadata when "exportWithFormatter" is false and the field type is number`, async () => {
10001002
mockColumns[5].exportWithFormatter = false; // "order" field that is of type number will be exported as a number cell format metadata
1001-
mockGridOptions.excelExportOptions.addGroupIndentation = false;
1003+
mockGridOptions.excelExportOptions!.addGroupIndentation = false;
10021004
const spyOnAfter = jest.spyOn(service.onGridAfterExportToExcel, 'next');
10031005
const spyUrlCreate = jest.spyOn(URL, 'createObjectURL');
10041006
const spyDownload = jest.spyOn(service, 'startDownloadFile');
@@ -1367,7 +1369,7 @@ describe('ExcelExportService', () => {
13671369
});
13681370

13691371
it(`should have the LastName header title translated when defined as a "headerKey" and "i18n" is set in grid option`, async () => {
1370-
mockGridOptions.excelExportOptions.sanitizeDataExport = false;
1372+
mockGridOptions.excelExportOptions!.sanitizeDataExport = false;
13711373
mockCollection2 = [{ id: 0, userId: '1E06', firstName: 'John', lastName: 'Z', position: 'SALES_REP', order: 10 }];
13721374
jest.spyOn(dataViewStub, 'getLength').mockReturnValue(mockCollection2.length);
13731375
jest.spyOn(dataViewStub, 'getItem').mockReturnValue(null).mockReturnValueOnce(mockCollection2[0]);

src/app/modules/angular-slickgrid/services/__tests__/export-utilities.spec.ts

+24-13
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,19 @@
11
import { exportWithFormatterWhenDefined } from '../export-utilities';
22
import { Column, Formatter, SlickGrid } from '../../models/index';
33

4+
const mockDataView = {
5+
constructor: jest.fn(),
6+
init: jest.fn(),
7+
destroy: jest.fn(),
8+
getItemMetadata: jest.fn(),
9+
};
10+
11+
const gridStub = {
12+
getData: () => mockDataView,
13+
};
14+
415
describe('Export Utilities', () => {
5-
let mockItem;
16+
let mockItem: any;
617
let mockColumn: Column;
718
const myBoldHtmlFormatter: Formatter = (_row, _cell, value) => value !== null ? { text: value ? `<b>${value}</b>` : '' } : null as any;
819
const myUppercaseFormatter: Formatter = (_row, _cell, value) => value ? { text: value.toUpperCase() } : null as any;
@@ -14,65 +25,65 @@ describe('Export Utilities', () => {
1425

1526
describe('exportWithFormatterWhenDefined method', () => {
1627
it('should NOT enable exportWithFormatter and expect the firstName to returned', () => {
17-
const output = exportWithFormatterWhenDefined(1, 1, mockItem, mockColumn, {} as SlickGrid, { exportWithFormatter: false });
28+
const output = exportWithFormatterWhenDefined(1, 1, mockItem, mockColumn, gridStub as SlickGrid, { exportWithFormatter: false });
1829
expect(output).toBe('John');
1930
});
2031

2132
it('should provide a column definition field defined with a dot (.) notation and expect a complex object result', () => {
22-
const output = exportWithFormatterWhenDefined(1, 1, mockItem, { ...mockColumn, field: 'address.zip' }, {} as SlickGrid, {});
33+
const output = exportWithFormatterWhenDefined(1, 1, mockItem, { ...mockColumn, field: 'address.zip' }, gridStub as SlickGrid, {});
2334
expect(output).toEqual({ zip: 12345 });
2435
});
2536

2637
it('should provide a column definition field defined with a dot (.) notation and expect an empty string when the complex result is an empty object', () => {
27-
const output = exportWithFormatterWhenDefined(1, 1, mockItem, { ...mockColumn, field: 'empty' }, {} as SlickGrid, {});
38+
const output = exportWithFormatterWhenDefined(1, 1, mockItem, { ...mockColumn, field: 'empty' }, gridStub as SlickGrid, {});
2839
expect(output).toEqual('');
2940
});
3041

3142
it('should provide a column definition field defined with a dot (.) notation and expect an empty string when the complex result is an empty object', () => {
32-
const output = exportWithFormatterWhenDefined(1, 1, mockItem, { ...mockColumn, field: 'empty' }, {} as SlickGrid, {});
43+
const output = exportWithFormatterWhenDefined(1, 1, mockItem, { ...mockColumn, field: 'empty' }, gridStub as SlickGrid, {});
3344
expect(output).toEqual('');
3445
});
3546

3647
it('should provide a exportCustomFormatter in the column definition and expect the output to be formatted', () => {
37-
const output = exportWithFormatterWhenDefined(1, 1, mockItem, { ...mockColumn, exportCustomFormatter: myBoldHtmlFormatter }, {} as SlickGrid, { exportWithFormatter: true });
48+
const output = exportWithFormatterWhenDefined(1, 1, mockItem, { ...mockColumn, exportCustomFormatter: myBoldHtmlFormatter }, gridStub as SlickGrid, { exportWithFormatter: true });
3849
expect(output).toBe('<b>John</b>');
3950
});
4051

4152
it('should provide a exportCustomFormatter in the column definition and expect empty string when associated item property is null', () => {
42-
const output = exportWithFormatterWhenDefined(1, 1, { ...mockItem, firstName: null }, { ...mockColumn, exportCustomFormatter: myBoldHtmlFormatter }, {} as SlickGrid, { exportWithFormatter: true });
53+
const output = exportWithFormatterWhenDefined(1, 1, { ...mockItem, firstName: null }, { ...mockColumn, exportCustomFormatter: myBoldHtmlFormatter }, gridStub as SlickGrid, { exportWithFormatter: true });
4354
expect(output).toBe('');
4455
});
4556

4657
it('should provide a exportCustomFormatter in the column definition and expect empty string when associated item property is undefined', () => {
47-
const output = exportWithFormatterWhenDefined(1, 1, { ...mockItem, firstName: undefined }, { ...mockColumn, exportCustomFormatter: myBoldHtmlFormatter }, {} as SlickGrid, { exportWithFormatter: true });
58+
const output = exportWithFormatterWhenDefined(1, 1, { ...mockItem, firstName: undefined }, { ...mockColumn, exportCustomFormatter: myBoldHtmlFormatter }, gridStub as SlickGrid, { exportWithFormatter: true });
4859
expect(output).toBe('');
4960
});
5061

5162
it('should enable exportWithFormatter as an exportOption and expect the firstName to be formatted', () => {
52-
const output = exportWithFormatterWhenDefined(1, 1, mockItem, mockColumn, {} as SlickGrid, { exportWithFormatter: true });
63+
const output = exportWithFormatterWhenDefined(1, 1, mockItem, mockColumn, gridStub as SlickGrid, { exportWithFormatter: true });
5364
expect(output).toBe('JOHN');
5465
});
5566

5667
it('should enable exportWithFormatter as a grid option and expect the firstName to be formatted', () => {
5768
mockColumn.exportWithFormatter = true;
58-
const output = exportWithFormatterWhenDefined(1, 1, mockItem, mockColumn, {} as SlickGrid, { exportWithFormatter: true });
69+
const output = exportWithFormatterWhenDefined(1, 1, mockItem, mockColumn, gridStub as SlickGrid, { exportWithFormatter: true });
5970
expect(output).toBe('JOHN');
6071
});
6172

6273
it('should enable exportWithFormatter as a grid option and expect empty string when associated item property is null', () => {
6374
mockColumn.exportWithFormatter = true;
64-
const output = exportWithFormatterWhenDefined(1, 1, { ...mockItem, firstName: null }, mockColumn, {} as SlickGrid, { exportWithFormatter: true });
75+
const output = exportWithFormatterWhenDefined(1, 1, { ...mockItem, firstName: null }, mockColumn, gridStub as SlickGrid, { exportWithFormatter: true });
6576
expect(output).toBe('');
6677
});
6778

6879
it('should enable exportWithFormatter as a grid option and expect empty string when associated item property is undefined', () => {
6980
mockColumn.exportWithFormatter = true;
70-
const output = exportWithFormatterWhenDefined(1, 1, { ...mockItem, firstName: undefined }, mockColumn, {} as SlickGrid, { exportWithFormatter: true });
81+
const output = exportWithFormatterWhenDefined(1, 1, { ...mockItem, firstName: undefined }, mockColumn, gridStub as SlickGrid, { exportWithFormatter: true });
7182
expect(output).toBe('');
7283
});
7384

7485
it('should expect empty string when associated item property is undefined and has no formatter defined', () => {
75-
const output = exportWithFormatterWhenDefined(1, 1, { ...mockItem, firstName: undefined }, mockColumn, {} as SlickGrid, {});
86+
const output = exportWithFormatterWhenDefined(1, 1, { ...mockItem, firstName: undefined }, mockColumn, gridStub as SlickGrid, {});
7687
expect(output).toBe('');
7788
});
7889
});

0 commit comments

Comments
 (0)