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..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 @@ -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/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..75287e67c94 100644 --- a/projects/igniteui-angular/src/lib/services/excel/excel-files.ts +++ b/projects/igniteui-angular/src/lib/services/excel/excel-files.ts @@ -116,12 +116,23 @@ 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 = ``; + 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); + + const xSplit = hasFrozenCols ? `xSplit="${frozenColumnCount}" ` : ''; + const ySplit = hasFrozenRows ? `ySplit="${frozenRowCount}" ` : ''; + const xySplit = (xSplit + ySplit).trim(); + freezePane = ``; } } const hasTable = !worksheetData.isEmpty && worksheetData.options.exportAsTable; 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/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/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 }; + } + } 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 d3848a00372..69e2412f8b8 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 a90fb557f5f..fda771b0795 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,14 @@ import { Component, OnInit, ViewChild } from '@angular/core'; -import { IgxGridComponent, ColumnPinningPosition, RowPinningPosition, IgxGridRowComponent, IgxTransactionService, IgxGridTransaction, IgxGridStateDirective } from 'igniteui-angular'; +import { + IgxGridComponent, + ColumnPinningPosition, + RowPinningPosition, IgxGridRowComponent, + IgxTransactionService, + IgxGridTransaction, + IgxGridStateDirective, + IgxExcelExporterService, + IgxExcelExporterOptions +} from 'igniteui-angular'; import { IPinningConfig } from 'projects/igniteui-angular/src/lib/grids/common/grid.interface'; @Component({ @@ -23,13 +32,16 @@ export class GridRowPinningSampleComponent implements OnInit { columns: false, rowPinning: true, pinningConfig: true - }; + }; @ViewChild('grid1', { static: true }) grid1: IgxGridComponent; @ViewChild(IgxGridStateDirective, { static: true }) public state: IgxGridStateDirective; + constructor(private excelExportService: IgxExcelExporterService) { + } + onRowChange() { if (this.pinningConfig.rows === RowPinningPosition.Bottom) { this.pinningConfig = { columns: this.pinningConfig.columns, rows: RowPinningPosition.Top }; @@ -42,7 +54,7 @@ export class GridRowPinningSampleComponent implements OnInit { if (this.pinningConfig.columns === ColumnPinningPosition.End) { this.pinningConfig = { columns: ColumnPinningPosition.Start, rows: this.pinningConfig.rows }; } else { - this.pinningConfig = { columns: ColumnPinningPosition.End, rows: this.pinningConfig.rows }; + this.pinningConfig = { columns: ColumnPinningPosition.End, rows: this.pinningConfig.rows }; } } @@ -53,7 +65,7 @@ export class GridRowPinningSampleComponent implements OnInit { this.columns = [ { field: 'ID', width: '200px', hidden: true }, { field: 'CompanyName', width: '200px', groupable: true }, - { field: 'ContactName', width: '200px', pinned: false, groupable: true }, + { field: 'ContactName', width: '200px', pinned: false, groupable: true }, { field: 'ContactTitle', width: '300px', pinned: false, groupable: true }, { field: 'Address', width: '250px' }, { field: 'City', width: '200px' }, @@ -98,28 +110,31 @@ export class GridRowPinningSampleComponent implements OnInit { togglePinRow(index) { const rec = this.data[index]; - this.grid1.isRecordPinned(rec)? - this.grid1.pinRow(this.data[index]) : - this.grid1.unpinRow(this.data[index]) + this.grid1.isRecordPinned(rec) ? + this.grid1.pinRow(this.data[index]) : + this.grid1.unpinRow(this.data[index]) } togglePining(row: IgxGridRowComponent, event) { event.preventDefault(); - if(row.pinned) { + if (row.pinned) { row.unpin(); } else { row.pin(); } } + public exportButtonHandler() { + this.excelExportService.export(this.grid1, new IgxExcelExporterOptions("ExportFileFromGrid")); + } + public saveGridState() { const state = this.state.getState() as string; window.localStorage.setItem("grid1-state", state); } - + public restoreGridState() { const state = window.localStorage.getItem("grid1-state"); this.state.setState(state); } - }