Skip to content
This repository was archived by the owner on Jun 1, 2025. It is now read-only.

Commit 6459035

Browse files
authored
Merge pull request #645 from ghiscoding/bugfix/export-empty-object
fix(exports): when cell value is empty object return empty string
2 parents cf69f5d + 0534d13 commit 6459035

File tree

4 files changed

+108
-14
lines changed

4 files changed

+108
-14
lines changed

src/app/modules/angular-slickgrid/formatters/__tests__/complexObjectFormatter.spec.ts

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { Column } from '../../models';
22
import { complexObjectFormatter } from '../complexObjectFormatter';
33

44
describe('the ComplexObject Formatter', () => {
5-
const allRoles = [{ roleId: 0, name: 'Administrator' }, { roleId: 1, name: 'Regular User' }];
5+
const allRoles = [{ roleId: 0, name: 'Administrator' }, { roleId: 1, name: 'Regular User', empty: {} }];
66

77
const dataset = [
88
{ id: 0, firstName: 'John', lastName: 'Smith', email: '[email protected]', role: allRoles[0] },
@@ -11,54 +11,60 @@ describe('the ComplexObject Formatter', () => {
1111
];
1212

1313
it('should throw an error when omitting to pass "complexFieldLabel" to "params"', () => {
14-
expect(() => complexObjectFormatter(0, 0, 'anything', {} as Column, {}, {}))
14+
expect(() => complexObjectFormatter(0, 0, 'anything', {} as Column, {}, {} as any))
1515
.toThrowError('For the Formatters.complexObject to work properly');
1616
});
1717

1818
it('should return empty string when no column definition is provided', () => {
19-
const result = complexObjectFormatter(0, 0, 'anything', null as Column, {}, {});
19+
const result = complexObjectFormatter(0, 0, 'anything', null as Column, {}, {} as any);
2020
expect(result).toBe('');
2121
});
2222

2323
it('should return original input value when the "field" property does not include a not ".", neither "complexFieldLabel"', () => {
24-
const result = complexObjectFormatter(0, 0, 'anything', { field: 'role' } as Column, {}, {});
24+
const result = complexObjectFormatter(0, 0, 'anything', { field: 'role' } as Column, {}, {} as any);
2525
expect(result).toBe('anything');
2626
});
2727

28-
it('should return original input value when the "field" property was not found in the data context object', () => {
29-
const result = complexObjectFormatter(0, 0, 'anything', { field: 'invalid.object' } as Column, dataset[2], {});
30-
expect(result).toBe('anything');
28+
it('should return empty string when the "field" property was not found in the data context object', () => {
29+
const result = complexObjectFormatter(0, 0, 'anything', { field: 'invalid.object' } as Column, dataset[2], {} as any);
30+
expect(result).toBe('');
3131
});
3232

3333
it('should return original input value when the "complexFieldLabel" does not include a not "." within its string', () => {
3434
const params = { complexFieldLabel: 'name' };
35-
const result = complexObjectFormatter(0, 0, 'anything', { field: 'role', params } as Column, {}, {});
35+
const result = complexObjectFormatter(0, 0, 'anything', { field: 'role', params } as Column, {}, {} as any);
3636
expect(result).toBe('anything');
3737
});
3838

3939
it('should return original input value when the "complexFieldLabel" was not found in the data context object', () => {
4040
const params = { complexFieldLabel: 'invalid.object' };
41-
const result = complexObjectFormatter(0, 0, 'anything', { field: 'role', params } as Column, dataset[2], {});
42-
expect(result).toBe('anything');
41+
const result = complexObjectFormatter(0, 0, 'anything', { field: 'role', params } as Column, dataset[2], {} as any);
42+
expect(result).toBe('');
4343
});
4444

4545
it('should return the value from the complex object when "field" property with dot notation was found in the data context object', () => {
4646
const expectedOutput = 'Administrator';
47-
const result = complexObjectFormatter(0, 0, 'anything', { field: 'role.name' } as Column, dataset[0], {});
47+
const result = complexObjectFormatter(0, 0, 'anything', { field: 'role.name' } as Column, dataset[0], {} as any);
48+
expect(result).toBe(expectedOutput);
49+
});
50+
51+
it('should return an empty string when the value from the complex object when "field" has dot notation and the empty returned from it is an empty object', () => {
52+
const expectedOutput = '';
53+
const result = complexObjectFormatter(0, 0, 'anything', { field: 'role.empty' } as Column, dataset[1], {} as any);
4854
expect(result).toBe(expectedOutput);
4955
});
5056

5157
it('should return the value from the complex object when "complexFieldLabel" property with dot notation was found in the data context object', () => {
5258
const params = { complexFieldLabel: 'role.name' };
5359
const expectedOutput = 'Administrator';
54-
const result = complexObjectFormatter(0, 0, 'anything', { field: 'role', params } as Column, dataset[0], {});
60+
const result = complexObjectFormatter(0, 0, 'anything', { field: 'role', params } as Column, dataset[0], {} as any);
5561
expect(result).toBe(expectedOutput);
5662
});
5763

5864
it('should return the value from the complex object when "complexFieldLabel" is not dot notation but has a "labelKey" was found in the data context object', () => {
5965
const params = { complexFieldLabel: 'role' };
6066
const expectedOutput = 'Administrator';
61-
const result = complexObjectFormatter(0, 0, 'anything', { field: 'role', labelKey: 'name', params } as Column, dataset[0], {});
67+
const result = complexObjectFormatter(0, 0, 'anything', { field: 'role', labelKey: 'name', params } as Column, dataset[0], {} as any);
6268
expect(result).toBe(expectedOutput);
6369
});
6470
});

src/app/modules/angular-slickgrid/formatters/complexObjectFormatter.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,11 @@ export const complexObjectFormatter: Formatter = (row: number, cell: number, cel
2424
// when complexFieldLabel includes the dot ".", we will do the split and get the value from the complex object
2525
// however we also need to make sure that the complex objet exist, else we'll return the cell value (original value)
2626
if (typeof complexFieldLabel === 'string' && complexFieldLabel.indexOf('.') > 0) {
27-
return complexFieldLabel.split('.').reduce((obj, i) => (obj && obj.hasOwnProperty(i) ? obj[i] : cellValue), dataContext);
27+
let outputValue = complexFieldLabel.split('.').reduce((obj, i) => (obj && obj.hasOwnProperty(i) ? obj[i] : ''), dataContext);
28+
if (typeof outputValue === 'object' && Object.entries(outputValue).length === 0) {
29+
outputValue = ''; // return empty string when value ends up being an empty object
30+
}
31+
return outputValue;
2832
}
2933
return cellValue;
3034
};
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import { exportWithFormatterWhenDefined } from '../export-utilities';
2+
import { Column, Formatter, SlickGrid } from '../../models/index';
3+
4+
describe('Export Utilities', () => {
5+
let mockItem;
6+
let mockColumn: Column;
7+
const myBoldHtmlFormatter: Formatter = (_row, _cell, value) => value !== null ? { text: value ? `<b>${value}</b>` : '' } : null as any;
8+
const myUppercaseFormatter: Formatter = (_row, _cell, value) => value ? { text: value.toUpperCase() } : null as any;
9+
10+
beforeEach(() => {
11+
mockItem = { firstName: 'John', lastName: 'Doe', age: 45, address: { zip: 12345 }, empty: {} };
12+
mockColumn = { id: 'firstName', name: 'First Name', field: 'firstName', formatter: myUppercaseFormatter };
13+
});
14+
15+
describe('exportWithFormatterWhenDefined method', () => {
16+
it('should NOT enable exportWithFormatter and expect the firstName to returned', () => {
17+
const output = exportWithFormatterWhenDefined(1, 1, mockItem, mockColumn, {} as SlickGrid, { exportWithFormatter: false });
18+
expect(output).toBe('John');
19+
});
20+
21+
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, {});
23+
expect(output).toEqual({ zip: 12345 });
24+
});
25+
26+
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, {});
28+
expect(output).toEqual('');
29+
});
30+
31+
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, {});
33+
expect(output).toEqual('');
34+
});
35+
36+
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 });
38+
expect(output).toBe('<b>John</b>');
39+
});
40+
41+
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 });
43+
expect(output).toBe('');
44+
});
45+
46+
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 });
48+
expect(output).toBe('');
49+
});
50+
51+
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 });
53+
expect(output).toBe('JOHN');
54+
});
55+
56+
it('should enable exportWithFormatter as a grid option and expect the firstName to be formatted', () => {
57+
mockColumn.exportWithFormatter = true;
58+
const output = exportWithFormatterWhenDefined(1, 1, mockItem, mockColumn, {} as SlickGrid, { exportWithFormatter: true });
59+
expect(output).toBe('JOHN');
60+
});
61+
62+
it('should enable exportWithFormatter as a grid option and expect empty string when associated item property is null', () => {
63+
mockColumn.exportWithFormatter = true;
64+
const output = exportWithFormatterWhenDefined(1, 1, { ...mockItem, firstName: null }, mockColumn, {} as SlickGrid, { exportWithFormatter: true });
65+
expect(output).toBe('');
66+
});
67+
68+
it('should enable exportWithFormatter as a grid option and expect empty string when associated item property is undefined', () => {
69+
mockColumn.exportWithFormatter = true;
70+
const output = exportWithFormatterWhenDefined(1, 1, { ...mockItem, firstName: undefined }, mockColumn, {} as SlickGrid, { exportWithFormatter: true });
71+
expect(output).toBe('');
72+
});
73+
74+
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, {});
76+
expect(output).toBe('');
77+
});
78+
});
79+
});

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,5 +52,10 @@ export function exportWithFormatterWhenDefined(row: number, col: number, dataCon
5252
}
5353
}
5454

55+
// if at the end we have an empty object, then replace it with an empty string
56+
if (typeof output === 'object' && Object.entries(output).length === 0) {
57+
output = '';
58+
}
59+
5560
return output;
5661
}

0 commit comments

Comments
 (0)