Skip to content

Commit f7bf723

Browse files
authored
Merge branch 'master' into rkaraivanov/grids-spa-and-wellbeing
2 parents 2f4aecf + 035c41b commit f7bf723

15 files changed

+614
-98
lines changed

CHANGELOG.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ All notable changes for each version of this project will be documented in this
1414
<igx-grid-toolbar-hiding [overlaySettings]="overlaySettingsAuto"></igx-grid-toolbar-hiding>
1515
</igx-grid-toolbar-actions>
1616
```
17-
- `Exporters`'s `columnExporting` event now supports changing the index of the column in the exported file.
1817
- `IgxPaginatorComponent`
1918
- Added `paging` and `pagingDone` events; `paging` event is cancellable and is emitted before pagination is performed, `pagingDone` event gives you information about the previous and the current page number and is not cancellable; Also `IgxPageSizeSelectorComponent` and `IgxPageNavigationComponent` are introduced and now the paginator components allows you to define a custom content, as it is shown in the example below:
2019
```html
@@ -27,7 +26,6 @@ All notable changes for each version of this project will be documented in this
2726
</igx-paginator-content>
2827
</igx-paginator>
2928
```
30-
3129
- `Exporters`'s `columnExporting` event now supports changing the index of the column in the exported file.
3230
```typescript
3331
this.excelExporterService.columnExporting.subscribe((col) => {
@@ -36,6 +34,9 @@ All notable changes for each version of this project will be documented in this
3634
}
3735
});
3836
```
37+
- `IgxExcelExporterService`
38+
- Added support for exporting the grids' multi-column headers to **Excel**. By default, the multi-column headers would be exported but this behavior can be controlled by the `ignoreMultiColumnHeaders` option off the IgxExcelExporterOptions object.
39+
3940
### General
4041
- `IgxPaginatorComponent`
4142
- Deprecated properties `selectLabel` and `prepositionPage` are now removed;

projects/igniteui-angular/src/lib/services/csv/csv-exporter.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,13 +47,14 @@ export class IgxCsvExporterService extends IgxBaseExporter {
4747

4848
private _stringData: string;
4949

50-
protected exportDataImplementation(data: IExportRecord[], options: IgxCsvExporterOptions) {
50+
protected exportDataImplementation(data: IExportRecord[], options: IgxCsvExporterOptions, done: () => void) {
5151
data = data.map((item) => item.data);
5252
const csvData = new CharSeparatedValueData(data, options.valueDelimiter);
5353
csvData.prepareDataAsync((r) => {
5454
this._stringData = r;
5555
this.saveFile(options);
5656
this.exportEnded.emit({ csvData: this._stringData });
57+
done();
5758
});
5859
}
5960

projects/igniteui-angular/src/lib/services/excel/excel-exporter-grid.spec.ts

Lines changed: 89 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import { TestBed, waitForAsync } from '@angular/core/testing';
2-
import { Component, ViewChild } from '@angular/core';
32
import { IgxGridModule } from '../../grids/grid/public_api';
43
import { IgxGridComponent } from '../../grids/grid/grid.component';
54
import { IColumnExportingEventArgs, IRowExportingEventArgs } from '../exporter-common/base-export-service';
@@ -15,7 +14,9 @@ import {
1514
ProductsComponent,
1615
GridIDNameJobTitleHireDataPerformanceComponent,
1716
GridHireDateComponent,
18-
GridExportGroupedDataComponent
17+
GridExportGroupedDataComponent,
18+
MultiColumnHeadersExportComponent,
19+
GridWithEmptyColumnsComponent
1920
} from '../../test-utils/grid-samples.spec';
2021
import { SampleTestData } from '../../test-utils/sample-test-data.spec';
2122
import { first } from 'rxjs/operators';
@@ -30,11 +31,14 @@ import { UIInteractions, wait } from '../../test-utils/ui-interactions.spec';
3031
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
3132
import { FilteringExpressionsTree } from '../../data-operations/filtering-expressions-tree';
3233
import { FilteringLogic } from '../../data-operations/filtering-expression.interface';
33-
import { IgxHierarchicalGridExportComponent } from '../../test-utils/hierarchical-grid-components.spec';
34+
import { IgxHierarchicalGridExportComponent,
35+
IgxHierarchicalGridMultiColumnHeadersExportComponent
36+
} from '../../test-utils/hierarchical-grid-components.spec';
3437
import { IgxHierarchicalGridModule,
3538
IgxHierarchicalGridComponent,
3639
} from '../../grids/hierarchical-grid/public_api';
3740
import { IgxHierarchicalRowComponent } from '../../grids/hierarchical-grid/hierarchical-row.component';
41+
import { GridFunctions } from '../../test-utils/grid-functions.spec';
3842

3943
describe('Excel Exporter', () => {
4044
configureTestSuite();
@@ -53,7 +57,9 @@ describe('Excel Exporter', () => {
5357
GridIDNameJobTitleHireDataPerformanceComponent,
5458
GridHireDateComponent,
5559
GridExportGroupedDataComponent,
56-
IgxHierarchicalGridExportComponent
60+
IgxHierarchicalGridExportComponent,
61+
MultiColumnHeadersExportComponent,
62+
IgxHierarchicalGridMultiColumnHeadersExportComponent
5763
],
5864
imports: [IgxGridModule, IgxTreeGridModule, IgxHierarchicalGridModule, NoopAnimationsModule]
5965
}).compileComponents();
@@ -689,8 +695,7 @@ describe('Excel Exporter', () => {
689695

690696
describe('', () => {
691697
let fix;
692-
let hGrid: IgxHierarchicalGridComponent;
693-
698+
let hGrid;
694699
beforeEach(waitForAsync(() => {
695700
options = createExportOptions('HierarchicalGridExcelExport');
696701
fix = TestBed.createComponent(IgxHierarchicalGridExportComponent);
@@ -705,12 +710,12 @@ describe('Excel Exporter', () => {
705710

706711
it('should export hierarchical grid respecting options width.', async () => {
707712
options = createExportOptions('HierarchicalGridExcelExport', 50);
713+
708714
await exportAndVerify(hGrid, options, actualData.exportHierarchicalDataWithColumnWidth);
709715
});
710716

711717
it('should export sorted hierarchical grid data', async () => {
712718
hGrid.sort({fieldName: 'GrammyNominations', dir: SortingDirection.Desc});
713-
714719
fix.detectChanges();
715720

716721
await exportAndVerify(hGrid, options, actualData.exportSortedHierarchicalData);
@@ -782,6 +787,17 @@ describe('Excel Exporter', () => {
782787
});
783788
});
784789

790+
describe('', () => {
791+
it('should export hierarchical grid with multi column headers', async () => {
792+
const fix = TestBed.createComponent(IgxHierarchicalGridMultiColumnHeadersExportComponent);
793+
fix.detectChanges();
794+
795+
const hGrid = fix.componentInstance.hGrid;
796+
options = createExportOptions('HierarchicalGridMCHExcelExport');
797+
await exportAndVerify(hGrid, options, actualData.exportHierarchicalDataWithMultiColumnHeaders);
798+
});
799+
});
800+
785801
describe('', () => {
786802
let fix;
787803
let treeGrid: IgxTreeGridComponent;
@@ -911,7 +927,7 @@ describe('Excel Exporter', () => {
911927
expect(error).toMatch('Can create an outline of up to eight levels!');
912928
});
913929

914-
it('should skip the formatter when columnExproting skipFormatter is true', async () => {
930+
it('should skip the formatter when columnExporting skipFormatter is true', async () => {
915931
treeGrid.columns[4].formatter = ((val: number) => {
916932
const t = Math.floor(val / 10);
917933
const o = val % 10;
@@ -958,6 +974,66 @@ describe('Excel Exporter', () => {
958974
});
959975
});
960976

977+
describe('', () => {
978+
let fix;
979+
let grid: IgxGridComponent;
980+
981+
beforeEach(waitForAsync(() => {
982+
options = createExportOptions('MultiColumnHeaderGridExcelExport');
983+
fix = TestBed.createComponent(MultiColumnHeadersExportComponent);
984+
fix.detectChanges();
985+
986+
grid = fix.componentInstance.grid;
987+
}));
988+
989+
it('should export grid with multi column headers', async () => {
990+
await exportAndVerify(grid, options, actualData.exportMultiColumnHeadersData, false);
991+
});
992+
993+
it('should export grid with multi column headers and moved column', async () => {
994+
grid.columns[0].move(2);
995+
fix.detectChanges();
996+
997+
await exportAndVerify(grid, options, actualData.exportMultiColumnHeadersDataWithMovedColumn, false);
998+
});
999+
1000+
it('should export grid with hidden column', async () => {
1001+
grid.columns[0].hidden = true;
1002+
fix.detectChanges();
1003+
1004+
await exportAndVerify(grid, options, actualData.exportMultiColumnHeadersDataWithHiddenColumn, false);
1005+
});
1006+
1007+
it('should export grid with hidden column and ignoreColumnVisibility set to true', async () => {
1008+
grid.columns[0].hidden = true;
1009+
options.ignoreColumnsVisibility = true;
1010+
fix.detectChanges();
1011+
1012+
await exportAndVerify(grid, options, actualData.exportMultiColumnHeadersDataWithIgnoreColumnVisibility, false);
1013+
});
1014+
1015+
it('should export grid with pinned column group', async () => {
1016+
grid.columns[1].pinned = true;
1017+
fix.detectChanges();
1018+
1019+
await exportAndVerify(grid, options, actualData.exportMultiColumnHeadersDataWithPinnedColumn, false);
1020+
});
1021+
1022+
it('should export grid with collapsed and expanded multi column headers', async () => {
1023+
GridFunctions.clickGroupExpandIndicator(fix, grid.columns[1]);
1024+
GridFunctions.clickGroupExpandIndicator(fix, grid.columns[7]);
1025+
fix.detectChanges();
1026+
await exportAndVerify(grid, options, actualData.exportCollapsedAndExpandedMultiColumnHeadersData, false);
1027+
});
1028+
1029+
it('should respect ignoreMultiColumnHeaders when set to true', async () => {
1030+
options.ignoreMultiColumnHeaders = true;
1031+
fix.detectChanges();
1032+
1033+
await exportAndVerify(grid, options, actualData.exportMultiColumnHeadersDataWithoutMultiColumnHeaders);
1034+
});
1035+
});
1036+
9611037
const getExportedData = (grid, exportOptions: IgxExcelExporterOptions) => {
9621038
const exportData = new Promise<JSZipWrapper>((resolve) => {
9631039
exporter.exportEnded.pipe(first()).subscribe((value) => {
@@ -1004,31 +1080,12 @@ describe('Excel Exporter', () => {
10041080
return opts;
10051081
};
10061082

1007-
const exportAndVerify = async (component, exportOptions, expectedData) => {
1083+
const exportAndVerify = async (component, exportOptions, expectedData, exportTable: boolean = true) => {
10081084
const isHGrid = component instanceof IgxHierarchicalGridComponent;
1085+
const shouldNotExportTable = isHGrid || !exportTable;
1086+
10091087
const wrapper = await getExportedData(component, exportOptions);
1010-
await wrapper.verifyStructure(isHGrid);
1011-
await wrapper.verifyDataFilesContent(expectedData, '', isHGrid);
1088+
await wrapper.verifyStructure(shouldNotExportTable);
1089+
await wrapper.verifyDataFilesContent(expectedData, '', shouldNotExportTable);
10121090
};
10131091
});
1014-
1015-
@Component({
1016-
template: `
1017-
<igx-grid #grid1 [data]="data">
1018-
<igx-column>
1019-
<ng-template igxCell>
1020-
<button>SimpleBtn</button>
1021-
</ng-template>
1022-
</igx-column>
1023-
<igx-column header="" field="ID"></igx-column>
1024-
<igx-column header=" " field=""></igx-column>
1025-
<igx-column header="Name" field="Name"></igx-column>
1026-
<igx-column header="JobTitle" field="JobTitle"></igx-column>
1027-
</igx-grid>`
1028-
})
1029-
1030-
export class GridWithEmptyColumnsComponent {
1031-
@ViewChild('grid1', { static: true }) public grid: IgxGridComponent;
1032-
1033-
public data = SampleTestData.personJobDataFull();
1034-
}

projects/igniteui-angular/src/lib/services/excel/excel-exporter.ts

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { ExcelElementsFactory } from './excel-elements-factory';
55
import { ExcelFolderTypes } from './excel-enums';
66
import { IgxExcelExporterOptions } from './excel-exporter-options';
77
import { IExcelFolder } from './excel-interfaces';
8-
import { ExportRecordType, IExportRecord, IgxBaseExporter, DEFAULT_OWNER } from '../exporter-common/base-export-service';
8+
import { ExportRecordType, IExportRecord, IgxBaseExporter, DEFAULT_OWNER, HeaderType } from '../exporter-common/base-export-service';
99
import { ExportUtilities } from '../exporter-common/export-utilities';
1010
import { WorksheetData } from './worksheet-data';
1111
import { IBaseEventArgs } from '../../core/utils';
@@ -74,15 +74,15 @@ export class IgxExcelExporterService extends IgxBaseExporter {
7474
}
7575
}
7676

77-
protected exportDataImplementation(data: IExportRecord[], options: IgxExcelExporterOptions): void {
77+
protected exportDataImplementation(data: IExportRecord[], options: IgxExcelExporterOptions, done: () => void): void {
7878
const firstDataElement = data[0];
7979
const isHierarchicalGrid = firstDataElement?.type === ExportRecordType.HierarchicalGridRecord;
8080

8181
let rootKeys;
8282
let columnCount;
8383
let columnWidths;
8484
let indexOfLastPinnedColumn;
85-
85+
let defaultOwner;
8686

8787
const columnsExceedLimit = typeof firstDataElement !== 'undefined' ?
8888
isHierarchicalGrid ?
@@ -111,9 +111,11 @@ export class IgxExcelExporterService extends IgxBaseExporter {
111111
.sort((a,b) => b - a)[0];
112112

113113
rootKeys = this._ownersMap.get(firstDataElement.owner).columns.map(c => c.header);
114+
defaultOwner = this._ownersMap.get(firstDataElement.owner);
114115
} else {
115-
const defaultOwner = this._ownersMap.get(DEFAULT_OWNER);
116-
const columns = defaultOwner.columns.filter(col => !col.skip);
116+
defaultOwner = this._ownersMap.get(DEFAULT_OWNER);
117+
const columns = defaultOwner.columns.filter(col => !col.skip && col.headerType === HeaderType.ColumnHeader);
118+
117119
columnWidths = defaultOwner.columnWidths;
118120
indexOfLastPinnedColumn = defaultOwner.indexOfLastPinnedColumn;
119121
columnCount = columns.length;
@@ -122,7 +124,8 @@ export class IgxExcelExporterService extends IgxBaseExporter {
122124
}
123125

124126
const worksheetData =
125-
new WorksheetData(data, options, this._sort, columnCount, rootKeys, indexOfLastPinnedColumn, columnWidths);
127+
new WorksheetData(data, options, this._sort, columnCount, rootKeys, indexOfLastPinnedColumn,
128+
columnWidths, defaultOwner, this._ownersMap);
126129

127130
this._xlsx = typeof (JSZip as any).default === 'function' ? new (JSZip as any).default() : new JSZip();
128131

@@ -133,6 +136,7 @@ export class IgxExcelExporterService extends IgxBaseExporter {
133136
this._xlsx.generateAsync(IgxExcelExporterService.ZIP_OPTIONS).then((result) => {
134137
this.saveFile(result, options.fileName);
135138
this.exportEnded.emit({ xlsx: this._xlsx });
139+
done();
136140
});
137141
});
138142
}

0 commit comments

Comments
 (0)