diff --git a/projects/igniteui-angular/src/lib/services/excel/excel-exporter-grid.spec.ts b/projects/igniteui-angular/src/lib/services/excel/excel-exporter-grid.spec.ts
index bd7d815ecb9..e7c8fdad036 100644
--- a/projects/igniteui-angular/src/lib/services/excel/excel-exporter-grid.spec.ts
+++ b/projects/igniteui-angular/src/lib/services/excel/excel-exporter-grid.spec.ts
@@ -42,7 +42,9 @@ import { IgxHierarchicalGridExportComponent,
IgxHierarchicalGridMCHCollapsibleComponent,
IgxHierarchicalGridMultiColumnHeaderIslandsExportComponent,
IgxHierarchicalGridMultiColumnHeadersExportComponent,
- IgxHierarchicalGridSummariesExportComponent
+ IgxHierarchicalGridSummariesExportComponent,
+ IgxHierarchicalGridEmptyDataExportComponent,
+ IgxHierarchicalGridMissingChildDataExportComponent
} from '../../test-utils/hierarchical-grid-components.spec';
import { IgxHierarchicalGridComponent } from '../../grids/hierarchical-grid/public_api';
import { IgxHierarchicalRowComponent } from '../../grids/hierarchical-grid/hierarchical-row.component';
@@ -77,6 +79,8 @@ describe('Excel Exporter', () => {
IgxPivotGridTestComplexHierarchyComponent,
IgxTreeGridSummariesKeyComponent,
IgxHierarchicalGridSummariesExportComponent,
+ IgxHierarchicalGridEmptyDataExportComponent,
+ IgxHierarchicalGridMissingChildDataExportComponent,
GroupedGridWithSummariesComponent,
GridCurrencySummariesComponent,
GridUserMeetingDataComponent,
@@ -930,6 +934,41 @@ describe('Excel Exporter', () => {
await exportAndVerify(hGrid, options, actualData.exportHierarchicalDataWithSkippedRows);
});
+
+ it('should export hierarchical grid with empty data without throwing error', async () => {
+ fix = TestBed.createComponent(IgxHierarchicalGridEmptyDataExportComponent);
+ fix.detectChanges();
+
+ hGrid = fix.componentInstance.hGrid;
+ options = createExportOptions('HierarchicalGridEmptyDataExcelExport');
+
+ await expectAsync(getExportedData(hGrid, options)).toBeResolved();
+ });
+
+ it('should export hierarchical grid with empty data and summaries without throwing error', async () => {
+ fix = TestBed.createComponent(IgxHierarchicalGridEmptyDataExportComponent);
+ fix.detectChanges();
+
+ hGrid = fix.componentInstance.hGrid;
+ const artistColumn = hGrid.columns.find(col => col.field === 'Artist');
+ artistColumn.hasSummary = true;
+ fix.detectChanges();
+
+ options = createExportOptions('HierarchicalGridEmptyDataWithSummariesExcelExport');
+ options.exportSummaries = true;
+
+ await expectAsync(getExportedData(hGrid, options)).toBeResolved();
+ });
+
+ it('should export hierarchical grid with missing child data key without throwing error', async () => {
+ fix = TestBed.createComponent(IgxHierarchicalGridMissingChildDataExportComponent);
+ fix.detectChanges();
+
+ hGrid = fix.componentInstance.hGrid;
+ options = createExportOptions('HierarchicalGridMissingChildDataExcelExport');
+
+ await expectAsync(getExportedData(hGrid, options)).toBeResolved();
+ });
});
describe('', () => {
@@ -1494,7 +1533,7 @@ describe('Excel Exporter', () => {
fix.componentInstance.data = SALES_DATA;
fix.componentInstance.pivotConfigHierarchy = {
rows: [
- {
+ {
memberName: 'All_Srep Code Alts',
enabled: true,
width: '150px',
diff --git a/projects/igniteui-angular/src/lib/services/excel/excel-exporter.ts b/projects/igniteui-angular/src/lib/services/excel/excel-exporter.ts
index 0aa6c387e9f..b0d1b1bc678 100644
--- a/projects/igniteui-angular/src/lib/services/excel/excel-exporter.ts
+++ b/projects/igniteui-angular/src/lib/services/excel/excel-exporter.ts
@@ -77,6 +77,10 @@ export class IgxExcelExporterService extends IgxBaseExporter {
const firstDataElement = data[0];
const isHierarchicalGrid = firstDataElement?.type === ExportRecordType.HierarchicalGridRecord;
const isPivotGrid = firstDataElement?.type === ExportRecordType.PivotGridRecord;
+ const ownersKeys = Array.from(this._ownersMap.keys());
+ const firstKey = ownersKeys[0];
+ const isHierarchicalGridByMap = firstKey && typeof firstKey !== 'string';
+ const filterColumns = (columns) => columns.filter(col => col.field !== GRID_LEVEL_COL && !col.skip && col.headerType === ExportHeaderType.ColumnHeader);
let rootKeys;
let columnCount;
@@ -113,20 +117,30 @@ export class IgxExcelExporterService extends IgxBaseExporter {
rootKeys = this._ownersMap.get(firstDataElement.owner).columns.filter(c => !c.skip).map(c => c.field);
defaultOwner = this._ownersMap.get(firstDataElement.owner);
} else {
- defaultOwner = this._ownersMap.get(DEFAULT_OWNER);
- const columns = defaultOwner.columns.filter(col => col.field !== GRID_LEVEL_COL && !col.skip && col.headerType === ExportHeaderType.ColumnHeader);
-
- columnWidths = defaultOwner.columnWidths;
- indexOfLastPinnedColumn = defaultOwner.indexOfLastPinnedColumn;
- columnCount = isPivotGrid ? columns.length + this.pivotGridFilterFieldsCount : columns.length;
- rootKeys = columns.map(c => c.field);
+ // Check if this is actually a hierarchical grid (when data only contains summary records)
+ defaultOwner = isHierarchicalGridByMap
+ ? this._ownersMap.get(firstKey)
+ : this._ownersMap.get(DEFAULT_OWNER) || this._ownersMap.get(firstKey);
+
+ if (defaultOwner) {
+ const columns = filterColumns(defaultOwner.columns);
+
+ columnWidths = defaultOwner.columnWidths;
+ indexOfLastPinnedColumn = defaultOwner.indexOfLastPinnedColumn;
+ columnCount = isPivotGrid ? columns.length + this.pivotGridFilterFieldsCount : columns.length;
+ rootKeys = columns.map(c => c.field);
+ }
}
} else {
- const ownersKeys = Array.from(this._ownersMap.keys());
+ // For hierarchical grids with empty data, use the grid instance; otherwise try DEFAULT_OWNER first
+ defaultOwner = isHierarchicalGridByMap
+ ? this._ownersMap.get(firstKey)
+ : this._ownersMap.get(DEFAULT_OWNER) || this._ownersMap.get(firstKey);
- defaultOwner = this._ownersMap.get(ownersKeys[0]);
- columnWidths = defaultOwner.columnWidths;
- columnCount = defaultOwner.columns.filter(col => col.field !== GRID_LEVEL_COL && !col.skip && col.headerType === ExportHeaderType.ColumnHeader).length;
+ if (defaultOwner) {
+ columnWidths = defaultOwner.columnWidths;
+ columnCount = filterColumns(defaultOwner.columns).length;
+ }
}
const worksheetData =
diff --git a/projects/igniteui-angular/src/lib/services/excel/excel-files.ts b/projects/igniteui-angular/src/lib/services/excel/excel-files.ts
index 95f41241b01..c4ec293fbf2 100644
--- a/projects/igniteui-angular/src/lib/services/excel/excel-files.ts
+++ b/projects/igniteui-angular/src/lib/services/excel/excel-files.ts
@@ -551,9 +551,15 @@ export class WorksheetFile implements IExcelFile {
}
private getSummaryFunction(type: string, key: string, dimensionMapKey: any, recordLevel: number, col: IColumnInfo): string {
- const dimensionMap = dimensionMapKey ? this.hierarchicalDimensionMap.get(dimensionMapKey) : this.dimensionMap;
+ const dimensionMap = dimensionMapKey ? (this.hierarchicalDimensionMap.get(dimensionMapKey) ?? this.dimensionMap) : this.dimensionMap;
+ if (!dimensionMap) {
+ return '';
+ }
const dimensions = dimensionMap.get(key);
const levelDimensions = dimensionMap.get(GRID_LEVEL_COL);
+ if (!dimensions || !levelDimensions) {
+ return '';
+ }
let func = '';
let funcType = '';
diff --git a/projects/igniteui-angular/src/lib/services/exporter-common/base-export-service.ts b/projects/igniteui-angular/src/lib/services/exporter-common/base-export-service.ts
index b32987f463b..d959d193c1a 100644
--- a/projects/igniteui-angular/src/lib/services/exporter-common/base-export-service.ts
+++ b/projects/igniteui-angular/src/lib/services/exporter-common/base-export-service.ts
@@ -258,7 +258,8 @@ export abstract class IgxBaseExporter {
const childLayoutList = grid.childLayoutList;
for (const island of childLayoutList) {
- this.mapHierarchicalGridColumns(island, grid.data[0]);
+ const gridData = grid.data && grid.data.length > 0 ? grid.data[0] : {};
+ this.mapHierarchicalGridColumns(island, gridData);
}
} else if (grid.type === 'pivot') {
this.pivotGridColumns = [];
@@ -1227,22 +1228,27 @@ export abstract class IgxBaseExporter {
let keyData;
if (island.autoGenerate) {
- keyData = gridData[island.key];
- const islandKeys = island.children.map(i => i.key);
+ keyData = gridData && gridData[island.key] ? gridData[island.key] : undefined;
+ const islandKeys = island.children && island.children.length > 0 ? island.children.map(i => i.key) : [];
- const islandData = keyData.map(i => {
- const newItem = {};
+ if (keyData && Array.isArray(keyData) && keyData.length > 0) {
+ const islandData = keyData.map(i => {
+ const newItem = {};
- Object.keys(i).map(k => {
- if (!islandKeys.includes(k)) {
- newItem[k] = i[k];
- }
- });
+ Object.keys(i).map(k => {
+ if (!islandKeys.includes(k)) {
+ newItem[k] = i[k];
+ }
+ });
- return newItem;
- });
+ return newItem;
+ });
- columnList = this.getAutoGeneratedColumns(islandData);
+ columnList = this.getAutoGeneratedColumns(islandData);
+ } else {
+ // If no data available, create empty column list
+ columnList = this.getAutoGeneratedColumns([{}]);
+ }
} else {
const islandColumnList = island.columns;
columnList = this.getColumns(islandColumnList);
@@ -1250,9 +1256,9 @@ export abstract class IgxBaseExporter {
this._ownersMap.set(island, columnList);
- if (island.children.length > 0) {
+ if (island.children && island.children.length > 0) {
for (const childIsland of island.children) {
- const islandKeyData = keyData !== undefined ? keyData[0] : {};
+ const islandKeyData = keyData && Array.isArray(keyData) && keyData.length > 0 ? keyData[0] : {};
this.mapHierarchicalGridColumns(childIsland, islandKeyData);
}
}
diff --git a/projects/igniteui-angular/src/lib/test-utils/hierarchical-grid-components.spec.ts b/projects/igniteui-angular/src/lib/test-utils/hierarchical-grid-components.spec.ts
index 8400b60b0d1..5e649cd006e 100644
--- a/projects/igniteui-angular/src/lib/test-utils/hierarchical-grid-components.spec.ts
+++ b/projects/igniteui-angular/src/lib/test-utils/hierarchical-grid-components.spec.ts
@@ -754,3 +754,44 @@ export class IgxHierarchicalGridDefaultComponent {
this.data = SampleTestData.hierarchicalGridSingersFullData();
}
}
+
+@Component({
+ template: `
+
+
+
+
+
+
+
+
+
+ `,
+ imports: [IgxHierarchicalGridComponent, IgxColumnComponent, IgxRowIslandComponent]
+})
+export class IgxHierarchicalGridEmptyDataExportComponent {
+ @ViewChild('hierarchicalGrid', { read: IgxHierarchicalGridComponent, static: true }) public hGrid: IgxHierarchicalGridComponent;
+ public data = [];
+}
+
+@Component({
+ template: `
+
+
+
+
+
+
+
+
+
+ `,
+ imports: [IgxHierarchicalGridComponent, IgxColumnComponent, IgxRowIslandComponent]
+})
+export class IgxHierarchicalGridMissingChildDataExportComponent {
+ @ViewChild('hierarchicalGrid', { read: IgxHierarchicalGridComponent, static: true }) public hGrid: IgxHierarchicalGridComponent;
+ // Data without the 'Albums' key that the row island expects
+ public data = [
+ { Artist: 'Artist1', Debut: 2000, GrammyNominations: 5, GrammyAwards: 2 }
+ ];
+}