From 8d264a1a1024f1ab017743a2ef881b173f21ae06 Mon Sep 17 00:00:00 2001 From: MKirova Date: Tue, 24 Mar 2020 13:43:12 +0200 Subject: [PATCH 1/5] feat(igxGrid): Export pinned rows to excel - basic functionality. --- .../src/lib/services/excel/excel-exporter.ts | 3 ++- .../src/lib/services/excel/excel-files.ts | 11 +++++++++++ .../src/lib/services/excel/worksheet-data.ts | 2 +- .../services/exporter-common/base-export-service.ts | 10 ++++++++++ src/app/grid-row-pinning/grid-row-pinning.sample.html | 1 + src/app/grid-row-pinning/grid-row-pinning.sample.ts | 9 ++++++++- 6 files changed, 33 insertions(+), 3 deletions(-) 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 450b0dd6be0..49240f57781 100644 --- a/projects/igniteui-angular/src/lib/services/excel/excel-exporter.ts +++ b/projects/igniteui-angular/src/lib/services/excel/excel-exporter.ts @@ -77,7 +77,8 @@ export class IgxExcelExporterService extends IgxBaseExporter { } } - const worksheetData = new WorksheetData(data, options, this._indexOfLastPinnedColumn, this._sort, this._isTreeGrid); + const worksheetData = new WorksheetData(data, options, this._indexOfLastPinnedColumn, + this._indexOfLastPinnedRow, this._sort, this._isTreeGrid); this._xlsx = new JSZip(); const rootFolder = ExcelElementsFactory.getExcelFolder(ExcelFolderTypes.RootExcelFolder); 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 8c643591fb7..833966e0e91 100644 --- a/projects/igniteui-angular/src/lib/services/excel/excel-files.ts +++ b/projects/igniteui-angular/src/lib/services/excel/excel-files.ts @@ -123,6 +123,17 @@ export class WorksheetFile implements IExcelFile { const firstCell = ExcelStrings.getExcelColumn(frozenColumnCount) + '1'; freezePane = ``; } + if (worksheetData.indexOfLastPinnedRow !== -1 && + !worksheetData.options.ignorePinning ) { + // header should also be fixed. + const frozenRowCount = worksheetData.indexOfLastPinnedRow + 2; + const hasFrozenCols = worksheetData.indexOfLastPinnedColumn !== -1; + const frozenColumnCount = hasFrozenCols ? worksheetData.indexOfLastPinnedColumn + 1 : null; + const frozenColumn = !hasFrozenCols ? 'A' : ExcelStrings.getExcelColumn(worksheetData.indexOfLastPinnedColumn + 1); + const firstCell = frozenColumn + (frozenRowCount + 1); + freezePane = ``; + } } const hasTable = !worksheetData.isEmpty && worksheetData.options.exportAsTable; diff --git a/projects/igniteui-angular/src/lib/services/excel/worksheet-data.ts b/projects/igniteui-angular/src/lib/services/excel/worksheet-data.ts index 4496edf0012..e68f709e0fe 100644 --- a/projects/igniteui-angular/src/lib/services/excel/worksheet-data.ts +++ b/projects/igniteui-angular/src/lib/services/excel/worksheet-data.ts @@ -11,7 +11,7 @@ export class WorksheetData { private _isSpecialData: boolean; constructor(private _data: any[], public options: IgxExcelExporterOptions, public indexOfLastPinnedColumn, - public sort: any, public isTreeGridData = false) { + public indexOfLastPinnedRow, public sort: any, public isTreeGridData = false) { this.initializeData(); } 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 5bd8fefe2e7..240f20ad02d 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 @@ -72,6 +72,7 @@ export abstract class IgxBaseExporter { protected _isTreeGrid = false; protected _indexOfLastPinnedColumn = -1; + protected _indexOfLastPinnedRow = -1; protected _sort = null; /** @@ -289,6 +290,14 @@ export abstract class IgxBaseExporter { } } + if (grid.hasPinnedRecords) { + + const pinnedRecs = data.filter(x => grid.isRecordPinned(x)); + const unpinnedRecs = data.filter(x => !grid.isRecordPinned(x)); + data = [ ...pinnedRecs, ... unpinnedRecs]; + this._indexOfLastPinnedRow = pinnedRecs.length - 1; + } + return data; } @@ -307,6 +316,7 @@ export abstract class IgxBaseExporter { private resetDefaults() { this._columnList = []; this._indexOfLastPinnedColumn = -1; + this._indexOfLastPinnedRow = -1; this._sort = null; this.flatRecords = []; } diff --git a/src/app/grid-row-pinning/grid-row-pinning.sample.html b/src/app/grid-row-pinning/grid-row-pinning.sample.html index 184cd8fa447..ec7c4d2cf29 100644 --- a/src/app/grid-row-pinning/grid-row-pinning.sample.html +++ b/src/app/grid-row-pinning/grid-row-pinning.sample.html @@ -3,6 +3,7 @@ Allows rows to be pinned to the beginning/end of the grid. +
diff --git a/src/app/grid-row-pinning/grid-row-pinning.sample.ts b/src/app/grid-row-pinning/grid-row-pinning.sample.ts index 24c7b90300d..ea6ade75e51 100644 --- a/src/app/grid-row-pinning/grid-row-pinning.sample.ts +++ b/src/app/grid-row-pinning/grid-row-pinning.sample.ts @@ -1,5 +1,5 @@ import { Component, OnInit, ViewChild } from '@angular/core'; -import { IgxGridComponent, ColumnPinningPosition, RowPinningPosition, IgxGridRowComponent, IgxTransactionService, IgxGridTransaction } from 'igniteui-angular'; +import { IgxGridComponent, ColumnPinningPosition, RowPinningPosition, IgxGridRowComponent, IgxTransactionService, IgxGridTransaction, IgxExcelExporterService, IgxExcelExporterOptions } from 'igniteui-angular'; import { IPinningConfig } from 'projects/igniteui-angular/src/lib/grids/common/grid.interface'; @Component({ @@ -15,6 +15,9 @@ export class GridRowPinningSampleComponent implements OnInit { @ViewChild('grid1', { static: true }) grid1: IgxGridComponent; + constructor(private excelExportService: IgxExcelExporterService) { + } + onRowChange() { if (this.pinningConfig.rows === RowPinningPosition.Bottom) { this.pinningConfig = { columns: this.pinningConfig.columns, rows: RowPinningPosition.Top }; @@ -97,4 +100,8 @@ export class GridRowPinningSampleComponent implements OnInit { } } + public exportButtonHandler() { + this.excelExportService.export(this.grid1, new IgxExcelExporterOptions("ExportFileFromGrid")); + } + } From fe71b16c27772f15fa82d83772c91c7199d4c9e6 Mon Sep 17 00:00:00 2001 From: MKirova Date: Tue, 24 Mar 2020 13:56:23 +0200 Subject: [PATCH 2/5] chore(*): Unify logic between column and row pinning export to excel. --- .../src/lib/services/excel/excel-files.ts | 32 +++++++++---------- 1 file changed, 15 insertions(+), 17 deletions(-) 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 833966e0e91..a30f72115d5 100644 --- a/projects/igniteui-angular/src/lib/services/excel/excel-files.ts +++ b/projects/igniteui-angular/src/lib/services/excel/excel-files.ts @@ -116,23 +116,21 @@ export class WorksheetFile implements IExcelFile { cols.push(''); - if (worksheetData.indexOfLastPinnedColumn !== -1 && - !worksheetData.options.ignorePinning && - !worksheetData.options.ignoreColumnsOrder) { - const frozenColumnCount = worksheetData.indexOfLastPinnedColumn + 1; - const firstCell = ExcelStrings.getExcelColumn(frozenColumnCount) + '1'; - freezePane = ``; - } - if (worksheetData.indexOfLastPinnedRow !== -1 && - !worksheetData.options.ignorePinning ) { - // header should also be fixed. - const frozenRowCount = worksheetData.indexOfLastPinnedRow + 2; - const hasFrozenCols = worksheetData.indexOfLastPinnedColumn !== -1; - const frozenColumnCount = hasFrozenCols ? worksheetData.indexOfLastPinnedColumn + 1 : null; - const frozenColumn = !hasFrozenCols ? 'A' : ExcelStrings.getExcelColumn(worksheetData.indexOfLastPinnedColumn + 1); - const firstCell = frozenColumn + (frozenRowCount + 1); - freezePane = ``; + const hasFrozenElements = !worksheetData.options.ignorePinning && + (worksheetData.indexOfLastPinnedColumn !== -1 || worksheetData.indexOfLastPinnedRow !== -1); + + if (hasFrozenElements) { + const hasFrozenCols = !worksheetData.options.ignoreColumnsOrder && worksheetData.indexOfLastPinnedColumn !== -1; + const hasFrozenRows = worksheetData.indexOfLastPinnedRow !== -1; + + const frozenColumnCount = hasFrozenCols ? worksheetData.indexOfLastPinnedColumn + 1 : null; + const frozenRowCount = hasFrozenRows ? worksheetData.indexOfLastPinnedRow + 2 : null; + + const frozenColumn = !hasFrozenCols ? 'A' : ExcelStrings.getExcelColumn(frozenColumnCount); + const firstCell = frozenColumn + (frozenRowCount + 1); + + freezePane = ``; } } const hasTable = !worksheetData.isEmpty && worksheetData.options.exportAsTable; From 6983283c5d18c95527e02ac00d270ad91edbe350 Mon Sep 17 00:00:00 2001 From: MKirova Date: Tue, 24 Mar 2020 14:58:19 +0200 Subject: [PATCH 3/5] chore(*): Fix tests. --- .../igniteui-angular/src/lib/services/excel/excel-files.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) 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 a30f72115d5..75287e67c94 100644 --- a/projects/igniteui-angular/src/lib/services/excel/excel-files.ts +++ b/projects/igniteui-angular/src/lib/services/excel/excel-files.ts @@ -129,8 +129,10 @@ export class WorksheetFile implements IExcelFile { const frozenColumn = !hasFrozenCols ? 'A' : ExcelStrings.getExcelColumn(frozenColumnCount); const firstCell = frozenColumn + (frozenRowCount + 1); - freezePane = ``; + const xSplit = hasFrozenCols ? `xSplit="${frozenColumnCount}" ` : ''; + const ySplit = hasFrozenRows ? `ySplit="${frozenRowCount}" ` : ''; + const xySplit = (xSplit + ySplit).trim(); + freezePane = ``; } } const hasTable = !worksheetData.isEmpty && worksheetData.options.exportAsTable; From bd90d3b1911e45fb5ff5b57a32900990db3b4343 Mon Sep 17 00:00:00 2001 From: MKirova Date: Tue, 24 Mar 2020 15:49:06 +0200 Subject: [PATCH 4/5] chore(*): Add simple test. --- .../services/excel/excel-exporter-grid.spec.ts | 13 ++++++++++++- .../excel/jszip-verification-wrapper.spec.ts | 8 ++++++++ .../exporter-common/test-methods.spec.ts | 17 +++++++++++++++++ 3 files changed, 37 insertions(+), 1 deletion(-) 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 2e67837ff49..fff031699ed 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 @@ -24,7 +24,7 @@ import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { FilteringExpressionsTree } from '../../data-operations/filtering-expressions-tree'; import { FilteringLogic } from '../../data-operations/filtering-expression.interface'; -describe('Excel Exporter', () => { +fdescribe('Excel Exporter', () => { configureTestSuite(); let exporter: IgxExcelExporterService; let actualData: FileContentData; @@ -214,6 +214,17 @@ describe('Excel Exporter', () => { await wrapper.verifyDataFilesContent(actualData.gridJobTitleIdFrozen, 'Not all pinned columns are frozen in the export!'); }); + it('should honor all pinned rows.', async() => { + const result = await TestMethods.createGridAndPinRow(0, 2); + const fix = result.fixture; + const grid = result.grid; + + const wrapper = await getExportedData(grid, options); + wrapper.verifyStructure(); + await wrapper.verifyPinRowData('', + 'Not all pinned rows are frozen in the export!'); + }); + it('should honor applied sorting.', async () => { const fix = TestBed.createComponent(GridIDNameJobTitleComponent); fix.detectChanges(); diff --git a/projects/igniteui-angular/src/lib/services/excel/jszip-verification-wrapper.spec.ts b/projects/igniteui-angular/src/lib/services/excel/jszip-verification-wrapper.spec.ts index ae9e116acdb..fddf70d81ad 100644 --- a/projects/igniteui-angular/src/lib/services/excel/jszip-verification-wrapper.spec.ts +++ b/projects/igniteui-angular/src/lib/services/excel/jszip-verification-wrapper.spec.ts @@ -141,6 +141,14 @@ export class JSZipWrapper { }); } + public async verifyPinRowData(pinData: string, message = '') { + let result; + await this.readDataFiles().then(() => { + result = this.dataFilesContent[1]; + expect(result.fileContent.indexOf(pinData) !== -1).toBeTruthy(message); + }); + } + /* Verifies the contents of all files and asserts the result. Optionally, a message can be passed in, which, if specified, will be shown in the beginning of the comparison result. */ public async verifyFilesContent(expectedData: IFileContent[], message = '') { diff --git a/projects/igniteui-angular/src/lib/services/exporter-common/test-methods.spec.ts b/projects/igniteui-angular/src/lib/services/exporter-common/test-methods.spec.ts index 776444bb5f4..b4c188dceec 100644 --- a/projects/igniteui-angular/src/lib/services/exporter-common/test-methods.spec.ts +++ b/projects/igniteui-angular/src/lib/services/exporter-common/test-methods.spec.ts @@ -50,4 +50,21 @@ export class TestMethods { return { fixture: fix, grid: myGrid }; } + + /* Creates an instance of GridDeclarationComponent and pins the rows with the specified indices. */ + public static async createGridAndPinRow(...rowIndices: any[]) { + const fix = TestBed.createComponent(GridIDNameJobTitleComponent); + fix.detectChanges(); + await wait(16); + + const myGrid = fix.componentInstance.grid; + + // Pin columns + rowIndices.forEach((i) => { + myGrid.getRowByIndex(i).pin(); + }); + + return { fixture: fix, grid: myGrid }; + } + } From 91e3cc12078a9f44ec1f751f824ba1694c1a8618 Mon Sep 17 00:00:00 2001 From: MKirova Date: Tue, 24 Mar 2020 15:50:29 +0200 Subject: [PATCH 5/5] chore(*): Remove fdescribe. --- .../src/lib/services/excel/excel-exporter-grid.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 fff031699ed..90b7bbce38c 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 @@ -24,7 +24,7 @@ import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { FilteringExpressionsTree } from '../../data-operations/filtering-expressions-tree'; import { FilteringLogic } from '../../data-operations/filtering-expression.interface'; -fdescribe('Excel Exporter', () => { +describe('Excel Exporter', () => { configureTestSuite(); let exporter: IgxExcelExporterService; let actualData: FileContentData;