Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -77,6 +79,8 @@ describe('Excel Exporter', () => {
IgxPivotGridTestComplexHierarchyComponent,
IgxTreeGridSummariesKeyComponent,
IgxHierarchicalGridSummariesExportComponent,
IgxHierarchicalGridEmptyDataExportComponent,
IgxHierarchicalGridMissingChildDataExportComponent,
GroupedGridWithSummariesComponent,
GridCurrencySummariesComponent,
GridUserMeetingDataComponent,
Expand Down Expand Up @@ -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('', () => {
Expand Down Expand Up @@ -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',
Expand Down
36 changes: 25 additions & 11 deletions projects/igniteui-angular/src/lib/services/excel/excel-exporter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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 =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 = '';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 = [];
Expand Down Expand Up @@ -1227,32 +1228,37 @@ 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);
}

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);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -754,3 +754,44 @@ export class IgxHierarchicalGridDefaultComponent {
this.data = SampleTestData.hierarchicalGridSingersFullData();
}
}

@Component({
template: `
<igx-hierarchical-grid [data]="data" [height]="'1200px'" [width]="'700px'" #hierarchicalGrid>
<igx-column field="Artist" [sortable]="true"></igx-column>
<igx-column field="Debut" [sortable]="true" dataType="number"></igx-column>
<igx-column field="GrammyNominations" header="Grammy Nominations" [sortable]="true"></igx-column>
<igx-column field="GrammyAwards" header="Grammy Awards" [sortable]="true"></igx-column>

<igx-row-island [key]="'Albums'" [autoGenerate]="true">
</igx-row-island>
</igx-hierarchical-grid>
`,
imports: [IgxHierarchicalGridComponent, IgxColumnComponent, IgxRowIslandComponent]
})
export class IgxHierarchicalGridEmptyDataExportComponent {
@ViewChild('hierarchicalGrid', { read: IgxHierarchicalGridComponent, static: true }) public hGrid: IgxHierarchicalGridComponent;
public data = [];
}

@Component({
template: `
<igx-hierarchical-grid [data]="data" [height]="'1200px'" [width]="'700px'" #hierarchicalGrid>
<igx-column field="Artist" [sortable]="true"></igx-column>
<igx-column field="Debut" [sortable]="true" dataType="number"></igx-column>
<igx-column field="GrammyNominations" header="Grammy Nominations" [sortable]="true"></igx-column>
<igx-column field="GrammyAwards" header="Grammy Awards" [sortable]="true"></igx-column>

<igx-row-island [key]="'Albums'" [autoGenerate]="true">
</igx-row-island>
</igx-hierarchical-grid>
`,
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 }
];
}
Loading