From c3a4b5fb5e6e963d06582d4ebed2c65e029fcecf Mon Sep 17 00:00:00 2001 From: VDyulgerov Date: Thu, 30 Sep 2021 16:53:40 +0300 Subject: [PATCH 01/36] feat(changes): push changes initial --- .../grid-pinning-actions.component.spec.ts | 2 +- .../src/lib/grids/grid-base.directive.ts | 42 +++++++++++++++++++ .../lib/grids/grid/grid-row-pinning.spec.ts | 32 +++++++++++++- .../grid-row-pinning.sample.ts | 6 +++ src/app/grid-state/grid-state.component.ts | 2 +- 5 files changed, 80 insertions(+), 4 deletions(-) diff --git a/projects/igniteui-angular/src/lib/action-strip/grid-actions/grid-pinning-actions.component.spec.ts b/projects/igniteui-angular/src/lib/action-strip/grid-actions/grid-pinning-actions.component.spec.ts index d952c06d818..25dc29dd3b5 100644 --- a/projects/igniteui-angular/src/lib/action-strip/grid-actions/grid-pinning-actions.component.spec.ts +++ b/projects/igniteui-angular/src/lib/action-strip/grid-actions/grid-pinning-actions.component.spec.ts @@ -60,7 +60,7 @@ describe('igxGridPinningActions #grid ', () => { expect(grid.pinnedRows.length).toBe(0); }); - it('should allow navigating to disabled row in unpinned area', async () => { + fit('should allow navigating to disabled row in unpinned area', async () => { grid.pinRow('FAMIA'); fixture.detectChanges(); diff --git a/projects/igniteui-angular/src/lib/grids/grid-base.directive.ts b/projects/igniteui-angular/src/lib/grids/grid-base.directive.ts index 3b516951edd..fbe4a5e285a 100644 --- a/projects/igniteui-angular/src/lib/grids/grid-base.directive.ts +++ b/projects/igniteui-angular/src/lib/grids/grid-base.directive.ts @@ -156,6 +156,7 @@ import { IgxPaginatorComponent } from '../paginator/paginator.component'; import { IgxGridHeaderRowComponent } from './headers/grid-header-row.component'; import { IgxGridGroupByAreaComponent } from './grouping/grid-group-by-area.component'; import { IgxFlatTransactionFactory, TRANSACTION_TYPE } from '../services/transaction/transaction-factory.service'; +import {IgxGridRow} from "./grid-public-row"; let FAKE_ROW_ID = -1; const DEFAULT_ITEMS_PER_PAGE = 15; @@ -913,6 +914,17 @@ export abstract class IgxGridBaseDirective extends DisplayDensityBase implements @Output() public rowPinning = new EventEmitter(); + /** + * Emitted when the pinned state of a row is changed. + * + * @example + * ```html + * + * ``` + */ + @Output() + public rowPinned = new EventEmitter(); + /** * Emmited when the active node is changed. * @@ -3696,6 +3708,22 @@ export abstract class IgxGridBaseDirective extends DisplayDensityBase implements .pipe(takeUntil(this.destroy$)) .subscribe((change: QueryList) => { this.onPinnedRowsChanged(change); + + /* debugger + if (change.last && change.last.pinned) { + const row = new IgxGridRow(change.last.grid, change.last.index, change.last.rowData); + const eventArgs: IPinRowEventArgs = { + insertAtIndex: change.last.index, + isPinned: true, + rowID: change.last.rowID, + row: row + }; + + //this.gridAPI.get_row_by_key(changel.last.index) + + this.rowPinned.emit(eventArgs); + }*/ + }); this.addRowSnackbar?.clicked.subscribe(() => { @@ -4779,9 +4807,11 @@ export abstract class IgxGridBaseDirective extends DisplayDensityBase implements * @param index The index at which to insert the row in the pinned collection. */ public pinRow(rowID: any, index?: number, row?: RowType): boolean { + debugger if (this._pinnedRecordIDs.indexOf(rowID) !== -1) { return false; } + const eventArgs: IPinRowEventArgs = { insertAtIndex: index, isPinned: true, @@ -4797,7 +4827,13 @@ export abstract class IgxGridBaseDirective extends DisplayDensityBase implements this.pipeTrigger++; if (this.gridAPI.grid) { this.notifyChanges(); + // Force pipe triggering + this.cdr.detectChanges(); + this.rowPinned.emit(eventArgs) } + + + return true; } @@ -4823,12 +4859,15 @@ export abstract class IgxGridBaseDirective extends DisplayDensityBase implements row }; this.rowPinning.emit(eventArgs); + this.crudService.endEdit(false); this._pinnedRecordIDs.splice(index, 1); this.pipeTrigger++; if (this.gridAPI.grid) { this.cdr.detectChanges(); + this.rowPinned.emit(eventArgs); } + return true; } @@ -6391,6 +6430,9 @@ export abstract class IgxGridBaseDirective extends DisplayDensityBase implements if (diff) { this.notifyChanges(true); } + + // debugger + // this.rowPinned.emit(); } /** diff --git a/projects/igniteui-angular/src/lib/grids/grid/grid-row-pinning.spec.ts b/projects/igniteui-angular/src/lib/grids/grid/grid-row-pinning.spec.ts index 248514873bd..3f7be573f15 100644 --- a/projects/igniteui-angular/src/lib/grids/grid/grid-row-pinning.spec.ts +++ b/projects/igniteui-angular/src/lib/grids/grid/grid-row-pinning.spec.ts @@ -177,6 +177,34 @@ describe('Row Pinning #grid', () => { expect(grid.rowPinning.emit).toHaveBeenCalledTimes(2); }); + it('should emit rowPinned on pin/unpin.', () => { + spyOn(grid.rowPinned, 'emit').and.callThrough(); + + let row = grid.getRowByIndex(0); + const rowID = row.key; + row.pin(); + fix.detectChanges(); + + // Check pinned state with getRowByIndex after pin action + expect(row.pinned).toBe(true); + + expect(grid.rowPinned.emit).toHaveBeenCalledTimes(1); + expect(grid.rowPinned.emit).toHaveBeenCalledWith({ + rowID, + insertAtIndex: undefined, + isPinned: true, + row + }); + + row = grid.getRowByIndex(0); + row.unpin(); + fix.detectChanges(); + // Check pinned state with getRowByIndex after unpin action + expect(row.pinned).toBe(false); + + expect(grid.rowPinned.emit).toHaveBeenCalledTimes(2); + }); + it('should pin/unpin via grid API methods.', () => { // pin 2nd row grid.pinRow(fix.componentInstance.data[1]); @@ -433,13 +461,13 @@ describe('Row Pinning #grid', () => { fix.detectChanges(); expect(grid.gridAPI.get_row_by_index(0).rowID).toBe(fix.componentInstance.data[1]); - expect(grid.gridAPI.get_row_by_index(1).rowID).toBe(fix.componentInstance.data[5]); + expect(grid.gridAPI.get_row_by_index(1).rowID).toBe(fix.componentInstance.data[4]); grid.sort({ fieldName: 'ID', dir: SortingDirection.Desc, ignoreCase: false }); fix.detectChanges(); // check pinned rows data is sorted - expect(grid.gridAPI.get_row_by_index(0).rowID).toBe(fix.componentInstance.data[5]); + expect(grid.gridAPI.get_row_by_index(0).rowID).toBe(fix.componentInstance.data[4]); expect(grid.gridAPI.get_row_by_index(1).rowID).toBe(fix.componentInstance.data[1]); // check unpinned rows data is sorted 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 f57fd1ea016..e774c13104f 100644 --- a/src/app/grid-row-pinning/grid-row-pinning.sample.ts +++ b/src/app/grid-row-pinning/grid-row-pinning.sample.ts @@ -45,6 +45,7 @@ export class GridRowPinningSampleComponent implements OnInit, AfterViewInit { groupBy: true, columns: false, rowPinning: true, + rowPinned: true, pinningConfig: true }; public selectionMode; @@ -178,6 +179,11 @@ export class GridRowPinningSampleComponent implements OnInit, AfterViewInit { ]; this.selectionMode = GridSelectionMode.multiple; /* eslint-enable max-len */ + + this.grid1.rowPinned.subscribe((event) => { + debugger + const row = this.state.getState(true, ['rowPinning']); // return value doesn't include the pinned row + }); } public ngAfterViewInit() { diff --git a/src/app/grid-state/grid-state.component.ts b/src/app/grid-state/grid-state.component.ts index 797b0dcd57a..5c8570abadb 100644 --- a/src/app/grid-state/grid-state.component.ts +++ b/src/app/grid-state/grid-state.component.ts @@ -91,7 +91,7 @@ export class GridSaveStateComponent implements OnInit, AfterViewInit { groupBy: true, columns: true, expansion: true, - rowPinning: true + rowPinning: true, }; public initialColumns: GridState [] = [ From 6d595016742fc6e89550a6a0d4702c43341d16b0 Mon Sep 17 00:00:00 2001 From: igdmdimitrov Date: Thu, 30 Sep 2021 18:31:41 +0300 Subject: [PATCH 02/36] feat(exporters): add providedIn root to exporters --- .../igniteui-angular/src/lib/services/csv/csv-exporter.ts | 4 +++- .../igniteui-angular/src/lib/services/excel/excel-exporter.ts | 4 +++- src/app/app.module.ts | 4 +--- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/projects/igniteui-angular/src/lib/services/csv/csv-exporter.ts b/projects/igniteui-angular/src/lib/services/csv/csv-exporter.ts index 668a1f2e07a..aa5d0c80c5a 100644 --- a/projects/igniteui-angular/src/lib/services/csv/csv-exporter.ts +++ b/projects/igniteui-angular/src/lib/services/csv/csv-exporter.ts @@ -31,7 +31,9 @@ export interface ICsvExportEndedEventArgs extends IBaseEventArgs { * this.csvExportService.exportData(this.localData, opt); * ``` */ -@Injectable() +@Injectable({ + providedIn: 'root', +}) export class IgxCsvExporterService extends IgxBaseExporter { /** * This event is emitted when the export process finishes. 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 d5c974a1de3..97cb16ba76f 100644 --- a/projects/igniteui-angular/src/lib/services/excel/excel-exporter.ts +++ b/projects/igniteui-angular/src/lib/services/excel/excel-exporter.ts @@ -39,7 +39,9 @@ const EXCEL_MAX_COLS = 16384; * this.excelExportService.exportData(this.localData, new IgxExcelExporterOptions("FileName")); * ``` */ -@Injectable() +@Injectable({ + providedIn: 'root', +}) export class IgxExcelExporterService extends IgxBaseExporter { private static ZIP_OPTIONS = { compression: 'DEFLATE', type: 'base64' } as JSZip.JSZipGeneratorOptions<'base64'>; diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 601603b71fd..628693a8d95 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -5,7 +5,7 @@ import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { NgModule } from '@angular/core'; import { - IgxIconModule, IgxBottomNavModule, IgxGridModule, IgxExcelExporterService, IgxCsvExporterService, IgxOverlayService, + IgxIconModule, IgxBottomNavModule, IgxGridModule, IgxOverlayService, IgxDragDropModule, IgxDividerModule, IgxTreeGridModule, IgxHierarchicalGridModule, IgxInputGroupModule, IgxIconService, DisplayDensityToken, DisplayDensity, IgxDateTimeEditorModule, IgxDateRangePickerModule, IgxButtonModule, IgxActionStripModule, GridBaseAPIService, IgxButtonGroupModule, @@ -327,9 +327,7 @@ const components = [ HierarchicalRemoteService, GridBaseAPIService, IgxGridHierarchicalPipe, - IgxExcelExporterService, IgxIconService, - IgxCsvExporterService, IgxOverlayService, { provide: DisplayDensityToken, useFactory: () => ({ displayDensity: DisplayDensity.comfortable }) }, { From aeebe049b396c4cdec3cfa5522d8acbdeb259e02 Mon Sep 17 00:00:00 2001 From: Hristo Anastasov Date: Thu, 30 Sep 2021 19:06:03 +0300 Subject: [PATCH 03/36] chore(*): remove fit from test --- .../grid-actions/grid-pinning-actions.component.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/projects/igniteui-angular/src/lib/action-strip/grid-actions/grid-pinning-actions.component.spec.ts b/projects/igniteui-angular/src/lib/action-strip/grid-actions/grid-pinning-actions.component.spec.ts index 25dc29dd3b5..d952c06d818 100644 --- a/projects/igniteui-angular/src/lib/action-strip/grid-actions/grid-pinning-actions.component.spec.ts +++ b/projects/igniteui-angular/src/lib/action-strip/grid-actions/grid-pinning-actions.component.spec.ts @@ -60,7 +60,7 @@ describe('igxGridPinningActions #grid ', () => { expect(grid.pinnedRows.length).toBe(0); }); - fit('should allow navigating to disabled row in unpinned area', async () => { + it('should allow navigating to disabled row in unpinned area', async () => { grid.pinRow('FAMIA'); fixture.detectChanges(); From 58aebb3a5b250fc8071b9a7ee2a33aa22ce8752b Mon Sep 17 00:00:00 2001 From: VDyulgerov Date: Fri, 1 Oct 2021 09:05:33 +0300 Subject: [PATCH 04/36] chore(*): fix lint errros --- .../src/lib/grids/grid-base.directive.ts | 23 ------------------- .../lib/grids/grid/grid-row-pinning.spec.ts | 4 ++-- .../grid-row-pinning.sample.ts | 5 ---- 3 files changed, 2 insertions(+), 30 deletions(-) diff --git a/projects/igniteui-angular/src/lib/grids/grid-base.directive.ts b/projects/igniteui-angular/src/lib/grids/grid-base.directive.ts index fbe4a5e285a..23de0f8fcb7 100644 --- a/projects/igniteui-angular/src/lib/grids/grid-base.directive.ts +++ b/projects/igniteui-angular/src/lib/grids/grid-base.directive.ts @@ -3708,22 +3708,6 @@ export abstract class IgxGridBaseDirective extends DisplayDensityBase implements .pipe(takeUntil(this.destroy$)) .subscribe((change: QueryList) => { this.onPinnedRowsChanged(change); - - /* debugger - if (change.last && change.last.pinned) { - const row = new IgxGridRow(change.last.grid, change.last.index, change.last.rowData); - const eventArgs: IPinRowEventArgs = { - insertAtIndex: change.last.index, - isPinned: true, - rowID: change.last.rowID, - row: row - }; - - //this.gridAPI.get_row_by_key(changel.last.index) - - this.rowPinned.emit(eventArgs); - }*/ - }); this.addRowSnackbar?.clicked.subscribe(() => { @@ -4807,7 +4791,6 @@ export abstract class IgxGridBaseDirective extends DisplayDensityBase implements * @param index The index at which to insert the row in the pinned collection. */ public pinRow(rowID: any, index?: number, row?: RowType): boolean { - debugger if (this._pinnedRecordIDs.indexOf(rowID) !== -1) { return false; } @@ -4827,13 +4810,10 @@ export abstract class IgxGridBaseDirective extends DisplayDensityBase implements this.pipeTrigger++; if (this.gridAPI.grid) { this.notifyChanges(); - // Force pipe triggering this.cdr.detectChanges(); this.rowPinned.emit(eventArgs) } - - return true; } @@ -6430,9 +6410,6 @@ export abstract class IgxGridBaseDirective extends DisplayDensityBase implements if (diff) { this.notifyChanges(true); } - - // debugger - // this.rowPinned.emit(); } /** diff --git a/projects/igniteui-angular/src/lib/grids/grid/grid-row-pinning.spec.ts b/projects/igniteui-angular/src/lib/grids/grid/grid-row-pinning.spec.ts index 3f7be573f15..440395f7194 100644 --- a/projects/igniteui-angular/src/lib/grids/grid/grid-row-pinning.spec.ts +++ b/projects/igniteui-angular/src/lib/grids/grid/grid-row-pinning.spec.ts @@ -461,13 +461,13 @@ describe('Row Pinning #grid', () => { fix.detectChanges(); expect(grid.gridAPI.get_row_by_index(0).rowID).toBe(fix.componentInstance.data[1]); - expect(grid.gridAPI.get_row_by_index(1).rowID).toBe(fix.componentInstance.data[4]); + expect(grid.gridAPI.get_row_by_index(1).rowID).toBe(fix.componentInstance.data[5]); grid.sort({ fieldName: 'ID', dir: SortingDirection.Desc, ignoreCase: false }); fix.detectChanges(); // check pinned rows data is sorted - expect(grid.gridAPI.get_row_by_index(0).rowID).toBe(fix.componentInstance.data[4]); + expect(grid.gridAPI.get_row_by_index(0).rowID).toBe(fix.componentInstance.data[5]); expect(grid.gridAPI.get_row_by_index(1).rowID).toBe(fix.componentInstance.data[1]); // check unpinned rows data is sorted 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 e774c13104f..fbdcd88c940 100644 --- a/src/app/grid-row-pinning/grid-row-pinning.sample.ts +++ b/src/app/grid-row-pinning/grid-row-pinning.sample.ts @@ -179,11 +179,6 @@ export class GridRowPinningSampleComponent implements OnInit, AfterViewInit { ]; this.selectionMode = GridSelectionMode.multiple; /* eslint-enable max-len */ - - this.grid1.rowPinned.subscribe((event) => { - debugger - const row = this.state.getState(true, ['rowPinning']); // return value doesn't include the pinned row - }); } public ngAfterViewInit() { From 5fed2279e2600d1cffd23c40a5095a369b3c26b5 Mon Sep 17 00:00:00 2001 From: VDyulgerov Date: Fri, 1 Oct 2021 09:20:29 +0300 Subject: [PATCH 05/36] chore(*): fix lint errros --- .../igniteui-angular/src/lib/grids/grid-base.directive.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/projects/igniteui-angular/src/lib/grids/grid-base.directive.ts b/projects/igniteui-angular/src/lib/grids/grid-base.directive.ts index 23de0f8fcb7..9187125427a 100644 --- a/projects/igniteui-angular/src/lib/grids/grid-base.directive.ts +++ b/projects/igniteui-angular/src/lib/grids/grid-base.directive.ts @@ -54,7 +54,6 @@ import { Action, } from '../services/public_api'; import { GridBaseAPIService } from './api.service'; -import { IgxGridCellComponent } from './cell.component'; import { ISummaryExpression } from './summaries/grid-summary'; import { RowEditPositionStrategy, IPinningConfig } from './grid.common'; import { IgxGridToolbarComponent } from './toolbar/grid-toolbar.component'; @@ -156,7 +155,6 @@ import { IgxPaginatorComponent } from '../paginator/paginator.component'; import { IgxGridHeaderRowComponent } from './headers/grid-header-row.component'; import { IgxGridGroupByAreaComponent } from './grouping/grid-group-by-area.component'; import { IgxFlatTransactionFactory, TRANSACTION_TYPE } from '../services/transaction/transaction-factory.service'; -import {IgxGridRow} from "./grid-public-row"; let FAKE_ROW_ID = -1; const DEFAULT_ITEMS_PER_PAGE = 15; @@ -4811,7 +4809,7 @@ export abstract class IgxGridBaseDirective extends DisplayDensityBase implements if (this.gridAPI.grid) { this.notifyChanges(); this.cdr.detectChanges(); - this.rowPinned.emit(eventArgs) + this.rowPinned.emit(eventArgs); } return true; From 35098687cca6728ad47bb2e81c65327601be43d1 Mon Sep 17 00:00:00 2001 From: VDyulgerov Date: Fri, 1 Oct 2021 13:36:00 +0300 Subject: [PATCH 06/36] fix(grid): fix 4 buggy tests --- .../src/lib/grids/grid/grid-row-pinning.spec.ts | 8 ++++---- .../hierarchical-grid.integration.spec.ts | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/projects/igniteui-angular/src/lib/grids/grid/grid-row-pinning.spec.ts b/projects/igniteui-angular/src/lib/grids/grid/grid-row-pinning.spec.ts index 440395f7194..aabce35ce7e 100644 --- a/projects/igniteui-angular/src/lib/grids/grid/grid-row-pinning.spec.ts +++ b/projects/igniteui-angular/src/lib/grids/grid/grid-row-pinning.spec.ts @@ -461,13 +461,13 @@ describe('Row Pinning #grid', () => { fix.detectChanges(); expect(grid.gridAPI.get_row_by_index(0).rowID).toBe(fix.componentInstance.data[1]); - expect(grid.gridAPI.get_row_by_index(1).rowID).toBe(fix.componentInstance.data[5]); + expect(grid.gridAPI.get_row_by_index(1).rowID).toBe(fix.componentInstance.data[4]); grid.sort({ fieldName: 'ID', dir: SortingDirection.Desc, ignoreCase: false }); fix.detectChanges(); // check pinned rows data is sorted - expect(grid.gridAPI.get_row_by_index(0).rowID).toBe(fix.componentInstance.data[5]); + expect(grid.gridAPI.get_row_by_index(0).rowID).toBe(fix.componentInstance.data[4]); expect(grid.gridAPI.get_row_by_index(1).rowID).toBe(fix.componentInstance.data[1]); // check unpinned rows data is sorted @@ -627,14 +627,14 @@ describe('Row Pinning #grid', () => { let rows = grid.rowList.toArray(); - [1, 2, 1, 2, 3, 4, 5].forEach((x, index) => expect(rows[index].cells.first.value).toEqual(x)); + [1, 1, 2, 3, 4, 5].forEach((x, index) => expect(rows[index].cells.first.value).toEqual(x)); grid.paginate(2); fix.detectChanges(); rows = grid.rowList.toArray(); - [1, 2, 11, 12].forEach((x, index) => expect(rows[index].cells.first.value).toEqual(x)); + [1, 11, 12].forEach((x, index) => expect(rows[index].cells.first.value).toEqual(x)); }); }); diff --git a/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.integration.spec.ts b/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.integration.spec.ts index 704a0d1beea..cdb6618dd43 100644 --- a/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.integration.spec.ts +++ b/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.integration.spec.ts @@ -1153,14 +1153,14 @@ describe('IgxHierarchicalGrid Integration #hGrid', () => { let rows = hierarchicalGrid.rowList.toArray(); - [0, 1, 0, 1, 2, 3, 4].forEach((x, index) => expect(parseInt(rows[index].cells.first.value, 10)).toEqual(x)); + [0, 0, 1, 2, 3, 4, 5].forEach((x, index) => expect(parseInt(rows[index].cells.first.value, 10)).toEqual(x)); hierarchicalGrid.paginate(6); fixture.detectChanges(); rows = hierarchicalGrid.rowList.toArray(); - [0, 1, 36, 37, 38, 39].forEach((x, index) => expect(parseInt(rows[index].cells.first.value, 10)).toEqual(x)); + [0, 36, 37, 38, 39].forEach((x, index) => expect(parseInt(rows[index].cells.first.value, 10)).toEqual(x)); }); }); }); From db6562a414b0c102e4f365508e24660076c8c48b Mon Sep 17 00:00:00 2001 From: VDyulgerov Date: Fri, 1 Oct 2021 14:11:57 +0300 Subject: [PATCH 07/36] fix(grid): fix tree-grid-integration test --- .../src/lib/grids/tree-grid/tree-grid-integration.spec.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid-integration.spec.ts b/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid-integration.spec.ts index a1f679fdf8a..3b8b59e96c9 100644 --- a/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid-integration.spec.ts +++ b/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid-integration.spec.ts @@ -1707,14 +1707,14 @@ describe('IgxTreeGrid - Integration #tGrid', () => { let rows = treeGrid.rowList.toArray(); - [147, 475, 147, 475, 957, 317, 711, 998].forEach((x, index) => expect(parseInt(rows[index].cells.first.value, 10)).toEqual(x)); + [147, 147, 475, 957, 317, 711, 998].forEach((x, index) => expect(parseInt(rows[index].cells.first.value, 10)).toEqual(x)); treeGrid.paginate(1); fix.detectChanges(); rows = treeGrid.rowList.toArray(); - [147, 475, 299, 19, 847, 663].forEach((x, index) => expect(parseInt(rows[index].cells.first.value, 10)).toEqual(x)); + [147, 299, 19, 847, 663].forEach((x, index) => expect(parseInt(rows[index].cells.first.value, 10)).toEqual(x)); }); it('should make a correct selection', () => { From 31c1ce6b71eaeaca9c108f7b7ae30ce1ffc2da51 Mon Sep 17 00:00:00 2001 From: VDyulgerov Date: Tue, 5 Oct 2021 11:57:05 +0300 Subject: [PATCH 08/36] fix(grid): fix 4 buggy tests This reverts commit 35098687cca6728ad47bb2e81c65327601be43d1. --- .../src/lib/grids/grid/grid-row-pinning.spec.ts | 8 ++++---- .../hierarchical-grid.integration.spec.ts | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/projects/igniteui-angular/src/lib/grids/grid/grid-row-pinning.spec.ts b/projects/igniteui-angular/src/lib/grids/grid/grid-row-pinning.spec.ts index aabce35ce7e..440395f7194 100644 --- a/projects/igniteui-angular/src/lib/grids/grid/grid-row-pinning.spec.ts +++ b/projects/igniteui-angular/src/lib/grids/grid/grid-row-pinning.spec.ts @@ -461,13 +461,13 @@ describe('Row Pinning #grid', () => { fix.detectChanges(); expect(grid.gridAPI.get_row_by_index(0).rowID).toBe(fix.componentInstance.data[1]); - expect(grid.gridAPI.get_row_by_index(1).rowID).toBe(fix.componentInstance.data[4]); + expect(grid.gridAPI.get_row_by_index(1).rowID).toBe(fix.componentInstance.data[5]); grid.sort({ fieldName: 'ID', dir: SortingDirection.Desc, ignoreCase: false }); fix.detectChanges(); // check pinned rows data is sorted - expect(grid.gridAPI.get_row_by_index(0).rowID).toBe(fix.componentInstance.data[4]); + expect(grid.gridAPI.get_row_by_index(0).rowID).toBe(fix.componentInstance.data[5]); expect(grid.gridAPI.get_row_by_index(1).rowID).toBe(fix.componentInstance.data[1]); // check unpinned rows data is sorted @@ -627,14 +627,14 @@ describe('Row Pinning #grid', () => { let rows = grid.rowList.toArray(); - [1, 1, 2, 3, 4, 5].forEach((x, index) => expect(rows[index].cells.first.value).toEqual(x)); + [1, 2, 1, 2, 3, 4, 5].forEach((x, index) => expect(rows[index].cells.first.value).toEqual(x)); grid.paginate(2); fix.detectChanges(); rows = grid.rowList.toArray(); - [1, 11, 12].forEach((x, index) => expect(rows[index].cells.first.value).toEqual(x)); + [1, 2, 11, 12].forEach((x, index) => expect(rows[index].cells.first.value).toEqual(x)); }); }); diff --git a/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.integration.spec.ts b/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.integration.spec.ts index cdb6618dd43..704a0d1beea 100644 --- a/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.integration.spec.ts +++ b/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.integration.spec.ts @@ -1153,14 +1153,14 @@ describe('IgxHierarchicalGrid Integration #hGrid', () => { let rows = hierarchicalGrid.rowList.toArray(); - [0, 0, 1, 2, 3, 4, 5].forEach((x, index) => expect(parseInt(rows[index].cells.first.value, 10)).toEqual(x)); + [0, 1, 0, 1, 2, 3, 4].forEach((x, index) => expect(parseInt(rows[index].cells.first.value, 10)).toEqual(x)); hierarchicalGrid.paginate(6); fixture.detectChanges(); rows = hierarchicalGrid.rowList.toArray(); - [0, 36, 37, 38, 39].forEach((x, index) => expect(parseInt(rows[index].cells.first.value, 10)).toEqual(x)); + [0, 1, 36, 37, 38, 39].forEach((x, index) => expect(parseInt(rows[index].cells.first.value, 10)).toEqual(x)); }); }); }); From ef50acfcb965beacc46bd36b43076b0eddc9f4a0 Mon Sep 17 00:00:00 2001 From: igdmdimitrov Date: Tue, 5 Oct 2021 12:20:40 +0300 Subject: [PATCH 09/36] fix(esf): add empty filter if no filter is applied --- .../src/lib/grids/filtering/grid-filtering.service.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/projects/igniteui-angular/src/lib/grids/filtering/grid-filtering.service.ts b/projects/igniteui-angular/src/lib/grids/filtering/grid-filtering.service.ts index b10da1a7f36..209e73f7b36 100644 --- a/projects/igniteui-angular/src/lib/grids/filtering/grid-filtering.service.ts +++ b/projects/igniteui-angular/src/lib/grids/filtering/grid-filtering.service.ts @@ -292,7 +292,8 @@ export class IgxFilteringService implements OnDestroy { this.clear_filter(field); // Wait for the change detection to update filtered data through the pipes and then emit the event. - requestAnimationFrame(() => this.grid.filteringDone.emit(null)); + const emptyFilter = new FilteringExpressionsTree(null, field); + requestAnimationFrame(() => this.grid.filteringDone.emit(emptyFilter)); if (field) { const expressions = this.getExpressions(field); From ff6e5bf6e288915c1524de94ccbe5bdd635f3d70 Mon Sep 17 00:00:00 2001 From: Hristo Anastasov Date: Tue, 5 Oct 2021 14:44:16 +0300 Subject: [PATCH 10/36] test(grid): dont use detect changes after pinning/unpinning --- .../src/lib/grids/grid-base.directive.ts | 1 - .../lib/grids/grid/grid-row-pinning.spec.ts | 50 +++++-------------- .../hierarchical-grid.integration.spec.ts | 8 --- .../tree-grid/tree-grid-integration.spec.ts | 25 +--------- 4 files changed, 13 insertions(+), 71 deletions(-) diff --git a/projects/igniteui-angular/src/lib/grids/grid-base.directive.ts b/projects/igniteui-angular/src/lib/grids/grid-base.directive.ts index ece5e4f612c..91e73a53a5d 100644 --- a/projects/igniteui-angular/src/lib/grids/grid-base.directive.ts +++ b/projects/igniteui-angular/src/lib/grids/grid-base.directive.ts @@ -4851,7 +4851,6 @@ export abstract class IgxGridBaseDirective extends DisplayDensityBase implements this._pinnedRecordIDs.splice(insertIndex, 0, rowID); this.pipeTrigger++; if (this.gridAPI.grid) { - this.notifyChanges(); this.cdr.detectChanges(); this.rowPinned.emit(eventArgs); } diff --git a/projects/igniteui-angular/src/lib/grids/grid/grid-row-pinning.spec.ts b/projects/igniteui-angular/src/lib/grids/grid/grid-row-pinning.spec.ts index aabce35ce7e..0d17736511e 100644 --- a/projects/igniteui-angular/src/lib/grids/grid/grid-row-pinning.spec.ts +++ b/projects/igniteui-angular/src/lib/grids/grid/grid-row-pinning.spec.ts @@ -155,7 +155,6 @@ describe('Row Pinning #grid', () => { let row = grid.getRowByIndex(0); const rowID = row.key; row.pin(); - fix.detectChanges(); // Check pinned state with getRowByIndex after pin action expect(row.pinned).toBe(true); @@ -163,14 +162,13 @@ describe('Row Pinning #grid', () => { expect(grid.rowPinning.emit).toHaveBeenCalledTimes(1); expect(grid.rowPinning.emit).toHaveBeenCalledWith({ rowID, - insertAtIndex: undefined, + insertAtIndex: 0, isPinned: true, row }); row = grid.getRowByIndex(0); row.unpin(); - fix.detectChanges(); // Check pinned state with getRowByIndex after unpin action expect(row.pinned).toBe(false); @@ -183,7 +181,6 @@ describe('Row Pinning #grid', () => { let row = grid.getRowByIndex(0); const rowID = row.key; row.pin(); - fix.detectChanges(); // Check pinned state with getRowByIndex after pin action expect(row.pinned).toBe(true); @@ -191,18 +188,22 @@ describe('Row Pinning #grid', () => { expect(grid.rowPinned.emit).toHaveBeenCalledTimes(1); expect(grid.rowPinned.emit).toHaveBeenCalledWith({ rowID, - insertAtIndex: undefined, + insertAtIndex: 0, isPinned: true, row }); - row = grid.getRowByIndex(0); row.unpin(); - fix.detectChanges(); // Check pinned state with getRowByIndex after unpin action expect(row.pinned).toBe(false); expect(grid.rowPinned.emit).toHaveBeenCalledTimes(2); + expect(grid.rowPinned.emit).toHaveBeenCalledWith({ + rowID, + insertAtIndex: 0, + isPinned: false, + row + }); }); it('should pin/unpin via grid API methods.', () => { @@ -251,7 +252,6 @@ describe('Row Pinning #grid', () => { // unpin row = grid.gridAPI.get_row_by_index(0); row.unpin(); - fix.detectChanges(); expect(grid.pinnedRows.length).toBe(0); pinRowContainer = fix.debugElement.queryAll(By.css(FIXED_ROW_CONTAINER)); @@ -457,17 +457,16 @@ describe('Row Pinning #grid', () => { it('should apply sorting to both pinned and unpinned rows.', () => { grid.gridAPI.get_row_by_index(1).pin(); - grid.gridAPI.get_row_by_index(5).pin(); - fix.detectChanges(); + grid.gridAPI.get_row_by_index(6).pin(); expect(grid.gridAPI.get_row_by_index(0).rowID).toBe(fix.componentInstance.data[1]); - expect(grid.gridAPI.get_row_by_index(1).rowID).toBe(fix.componentInstance.data[4]); + expect(grid.gridAPI.get_row_by_index(1).rowID).toBe(fix.componentInstance.data[5]); grid.sort({ fieldName: 'ID', dir: SortingDirection.Desc, ignoreCase: false }); fix.detectChanges(); // check pinned rows data is sorted - expect(grid.gridAPI.get_row_by_index(0).rowID).toBe(fix.componentInstance.data[4]); + expect(grid.gridAPI.get_row_by_index(0).rowID).toBe(fix.componentInstance.data[5]); expect(grid.gridAPI.get_row_by_index(1).rowID).toBe(fix.componentInstance.data[1]); // check unpinned rows data is sorted @@ -601,7 +600,6 @@ describe('Row Pinning #grid', () => { it('should correctly apply paging state for grid and paginator when there are pinned rows.', () => { // pin the first row grid.gridAPI.get_row_by_index(0).pin(); - fix.detectChanges(); expect(grid.rowList.length).toEqual(6); expect(grid.perPage).toEqual(5); @@ -611,7 +609,6 @@ describe('Row Pinning #grid', () => { // pin the second row grid.gridAPI.get_row_by_index(2).pin(); - fix.detectChanges(); expect(grid.rowList.length).toEqual(7); expect(grid.perPage).toEqual(5); @@ -622,8 +619,6 @@ describe('Row Pinning #grid', () => { it('should have the correct records shown for pages with pinned rows', () => { grid.gridAPI.get_row_by_index(0).pin(); - grid.gridAPI.get_row_by_index(1).pin(); - fix.detectChanges(); let rows = grid.rowList.toArray(); @@ -634,7 +629,7 @@ describe('Row Pinning #grid', () => { rows = grid.rowList.toArray(); - [1, 11, 12].forEach((x, index) => expect(rows[index].cells.first.value).toEqual(x)); + [1, 11, 12].forEach((x, index) => expect(rows[index].cells.first.value).toEqual(x)); }); }); @@ -833,10 +828,8 @@ describe('Row Pinning #grid', () => { // Pin/Unpin with the methods firstRow.unpin(); expect(firstRow.pinned).toBe(false); - fix.detectChanges(); firstRow.pin(); expect(firstRow.pinned).toBe(true); - fix.detectChanges(); // Check again pinned row presence pinRowContainer = fix.debugElement.queryAll(By.css(FIXED_ROW_CONTAINER)); @@ -883,7 +876,6 @@ describe('Row Pinning #grid', () => { it('should hide columns in pinned and unpinned area', () => { // pin 2nd data row grid.pinRow(fix.componentInstance.data[1]); - fix.detectChanges(); const hiddenCol = grid.columns[1]; hiddenCol.hidden = true; fix.detectChanges(); @@ -920,14 +912,9 @@ describe('Row Pinning #grid', () => { it('should keep the scrollbar sizes correct when partially filtering out pinned records', () => { grid.gridAPI.get_row_by_index(1).pin(); - fix.detectChanges(); grid.gridAPI.get_row_by_index(3).pin(); - fix.detectChanges(); grid.gridAPI.get_row_by_index(5).pin(); - fix.detectChanges(); grid.gridAPI.get_row_by_index(7).pin(); - fix.detectChanges(); - fix.detectChanges(); // 4 records pinned + 2px border expect(grid.pinnedRowHeight).toBe(4 * grid.renderedRowHeight + 2); @@ -957,9 +944,7 @@ describe('Row Pinning #grid', () => { it('should enter edit mode for the next editable cell when tabbing.', () => { const gridContent = GridFunctions.getGridContent(fix); grid.gridAPI.get_row_by_index(0).pin(); - fix.detectChanges(); grid.gridAPI.get_row_by_index(3).pin(); - fix.detectChanges(); const firstEditable = grid.gridAPI.get_cell_by_index(0, 'CompanyName'); const secondEditable = grid.gridAPI.get_cell_by_index(1, 'CompanyName'); @@ -995,9 +980,7 @@ describe('Row Pinning #grid', () => { it('should enter edit mode for the previous editable cell when shift+tabbing.', () => { const gridContent = GridFunctions.getGridContent(fix); grid.gridAPI.get_row_by_index(0).pin(); - fix.detectChanges(); grid.gridAPI.get_row_by_index(3).pin(); - fix.detectChanges(); const firstEditable = grid.gridAPI.get_cell_by_index(0, 'CompanyName'); const secondEditable = grid.gridAPI.get_cell_by_index(1, 'CompanyName'); @@ -1045,7 +1028,6 @@ describe('Row Pinning #grid', () => { it('should navigate to bottom from top pinned row using Ctrl+ArrowDown', async () => { grid.gridAPI.get_row_by_index(5).pin(); - fix.detectChanges(); const firstRowCell = grid.gridAPI.get_row_by_index(0).cells.toArray()[1]; UIInteractions.simulateClickAndSelectEvent(firstRowCell); @@ -1067,7 +1049,6 @@ describe('Row Pinning #grid', () => { it('should navigate and scroll to first unpinned row from top pinned row using ArrowDown', async () => { grid.gridAPI.get_row_by_index(5).pin(); - fix.detectChanges(); grid.navigateTo(10); await wait(DEBOUNCE_TIME); @@ -1092,7 +1073,6 @@ describe('Row Pinning #grid', () => { it('should navigate to top pinned row from bottom unpinned row without scrolling using Ctrl+ArrowUp', async () => { grid.gridAPI.get_row_by_index(5).pin(); - fix.detectChanges(); grid.navigateTo(27); await wait(DEBOUNCE_TIME); @@ -1123,7 +1103,6 @@ describe('Row Pinning #grid', () => { it('should navigate to top pinned row from first unpinned row using ArrowUp', async () => { grid.gridAPI.get_row_by_index(5).pin(); grid.gridAPI.get_row_by_index(1).pin(); - fix.detectChanges(); const thirdRowCell = grid.gridAPI.get_row_by_index(2).cells.toArray()[1]; UIInteractions.simulateClickAndSelectEvent(thirdRowCell); @@ -1146,7 +1125,6 @@ describe('Row Pinning #grid', () => { it('should navigate and scroll to top from bottom pinned row using Ctrl+ArrowUp', async () => { fix.componentInstance.pinningConfig = { columns: ColumnPinningPosition.Start, rows: RowPinningPosition.Bottom }; grid.gridAPI.get_row_by_index(5).pin(); - fix.detectChanges(); grid.navigateTo(26); await wait(DEBOUNCE_TIME); @@ -1199,7 +1177,6 @@ describe('Row Pinning #grid', () => { it('should navigate to bottom pinned row from top unpinned row without scrolling using Ctrl+ArrowDown', async () => { fix.componentInstance.pinningConfig = { columns: ColumnPinningPosition.Start, rows: RowPinningPosition.Bottom }; grid.gridAPI.get_row_by_index(5).pin(); - fix.detectChanges(); expect(grid.verticalScrollContainer.getScroll().scrollTop).toEqual(0); @@ -1227,7 +1204,6 @@ describe('Row Pinning #grid', () => { grid.gridAPI.get_row_by_index(5).pin(); grid.gridAPI.get_row_by_index(1).pin(); await wait(DEBOUNCE_TIME); - fix.detectChanges(); grid.navigateTo(26); await wait(DEBOUNCE_TIME); @@ -1256,8 +1232,6 @@ describe('Row Pinning #grid', () => { it('should navigate down from pinned to unpinned row when there are filtered out pinned rows', async () => { grid.gridAPI.get_row_by_index(5).pin(); grid.gridAPI.get_row_by_index(1).pin(); - fix.detectChanges(); - grid.filter('ID', 'B', IgxStringFilteringOperand.instance().condition('contains'), false); fix.detectChanges(); diff --git a/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.integration.spec.ts b/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.integration.spec.ts index cdb6618dd43..e383cb522ec 100644 --- a/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.integration.spec.ts +++ b/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.integration.spec.ts @@ -866,15 +866,12 @@ describe('IgxHierarchicalGrid Integration #hGrid', () => { it('should pin rows to top ', (() => { hierarchicalGrid.pinRow('0'); - fixture.detectChanges(); expect(hierarchicalGrid.pinnedRows.length).toBe(1); hierarchicalGrid.unpinRow('0'); - fixture.detectChanges(); expect(hierarchicalGrid.pinnedRows.length).toBe(0); hierarchicalGrid.pinRow('0'); - fixture.detectChanges(); expect(hierarchicalGrid.pinnedRows.length).toBe(1); let pinRowContainer = fixture.debugElement.queryAll(By.css(FIXED_ROW_CONTAINER)); @@ -888,7 +885,6 @@ describe('IgxHierarchicalGrid Integration #hGrid', () => { expect(hierarchicalGrid.getRowByIndex(3).key).toBe('2'); hierarchicalGrid.pinRow('2'); - fixture.detectChanges(); pinRowContainer = fixture.debugElement.queryAll(By.css(FIXED_ROW_CONTAINER)); expect(pinRowContainer[0].children.length).toBe(2); @@ -1107,7 +1103,6 @@ describe('IgxHierarchicalGrid Integration #hGrid', () => { const paginator = fixture.debugElement.query(By.directive(IgxPaginatorComponent)).componentInstance; // pin the first row hierarchicalGrid.getRowByIndex(0).pin(); - fixture.detectChanges(); expect(hierarchicalGrid.rowList.length).toEqual(6); expect(hierarchicalGrid.perPage).toEqual(5); @@ -1117,7 +1112,6 @@ describe('IgxHierarchicalGrid Integration #hGrid', () => { // pin the second row hierarchicalGrid.getRowByIndex(2).pin(); - fixture.detectChanges(); expect(hierarchicalGrid.rowList.length).toEqual(7); expect(hierarchicalGrid.perPage).toEqual(5); @@ -1148,8 +1142,6 @@ describe('IgxHierarchicalGrid Integration #hGrid', () => { hierarchicalGrid.height = '700px'; fixture.detectChanges(); hierarchicalGrid.getRowByIndex(0).pin(); - hierarchicalGrid.getRowByIndex(1).pin(); - fixture.detectChanges(); let rows = hierarchicalGrid.rowList.toArray(); diff --git a/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid-integration.spec.ts b/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid-integration.spec.ts index 3b8b59e96c9..233421a939a 100644 --- a/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid-integration.spec.ts +++ b/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid-integration.spec.ts @@ -1470,7 +1470,6 @@ describe('IgxTreeGrid - Integration #tGrid', () => { it('should pin/unpin a row', () => { treeGrid.pinRow(711); - fix.detectChanges(); expect(treeGrid.pinnedRecordsCount).toBe(1); expect(treeGrid.getRowByKey(711).pinned).toBe(true); @@ -1482,11 +1481,9 @@ describe('IgxTreeGrid - Integration #tGrid', () => { expect(treeGrid.getRowByKey(711).pinned).toBe(false); treeGrid.getRowByKey(711).pin(); - fix.detectChanges(); expect(treeGrid.pinnedRecordsCount).toBe(1); treeGrid.getRowByKey(711).unpin(); - fix.detectChanges(); expect(treeGrid.pinnedRecordsCount).toBe(0); @@ -1505,7 +1502,6 @@ describe('IgxTreeGrid - Integration #tGrid', () => { const visibleRecordsLength = treeGrid.records.size; treeGrid.pinRow(711); - fix.detectChanges(); expect(treeGrid.getRowByIndex(visibleRecordsLength).key).toBe(711); }); @@ -1515,7 +1511,6 @@ describe('IgxTreeGrid - Integration #tGrid', () => { const secondRow = treeGrid.getRowByIndex(1); treeGrid.pinRow(711); - fix.detectChanges(); await wait(); @@ -1524,7 +1519,6 @@ describe('IgxTreeGrid - Integration #tGrid', () => { expect(treeGrid.getRowByIndex(2).key).toBe(secondRow.key); treeGrid.unpinRow(711); - fix.detectChanges(); await wait(); @@ -1537,13 +1531,11 @@ describe('IgxTreeGrid - Integration #tGrid', () => { const primaryKey = treeGrid.primaryKey; treeGrid.pinRow(rowToPin.data[primaryKey]); - fix.detectChanges(); expect(treeGrid.gridAPI.get_row_by_index(0).disabled).toBe(false); expect(treeGrid.gridAPI.get_row_by_index(1).disabled).toBe(true); treeGrid.unpinRow(rowToPin.data[primaryKey]); - fix.detectChanges(); expect(treeGrid.gridAPI.get_row_by_index(0).disabled).toBe(false); expect(treeGrid.gridAPI.get_row_by_index(1).disabled).toBe(false); @@ -1555,8 +1547,6 @@ describe('IgxTreeGrid - Integration #tGrid', () => { const primaryKey = treeGrid.primaryKey; treeGrid.pinRow(rowToPin.data[primaryKey]); - fix.detectChanges(); - fix.detectChanges(); const firstColumnField = treeGrid.columns[0].field; const pinnedChipPosition = treeGrid.gridAPI.get_cell_by_index(1, firstColumnField); @@ -1573,7 +1563,6 @@ describe('IgxTreeGrid - Integration #tGrid', () => { const primaryKey = treeGrid.primaryKey; treeGrid.pinRow(rowToPin.data[primaryKey]); - fix.detectChanges(); const thirdColumnField = treeGrid.columns[2].field; @@ -1590,7 +1579,6 @@ describe('IgxTreeGrid - Integration #tGrid', () => { const rowToPin = treeGrid.getRowByIndex(0); rowToPin.pin(); - fix.detectChanges(); // collapse pinned row treeGrid.toggleRow(rowToPin.key); @@ -1613,7 +1601,6 @@ describe('IgxTreeGrid - Integration #tGrid', () => { const rowToPin = treeGrid.getRowByIndex(0); rowToPin.pin(); - fix.detectChanges(); searchResultsCount = treeGrid.findNext('John'); expect(searchResultsCount).toBe(2); @@ -1622,7 +1609,6 @@ describe('IgxTreeGrid - Integration #tGrid', () => { it('should apply filtering to both pinned and unpinned rows', () => { treeGrid.pinRow(147); treeGrid.pinRow(711); - fix.detectChanges(); treeGrid.filter('ID', 147, IgxStringFilteringOperand.instance().condition('contains'), false); fix.detectChanges(); @@ -1635,8 +1621,7 @@ describe('IgxTreeGrid - Integration #tGrid', () => { it('should apply sorting to both pinned and unpinned rows', () => { treeGrid.pinRow(147); - treeGrid.pinRow(711); - fix.detectChanges(); + treeGrid.pinRow(711);; expect(treeGrid.getRowByIndex(0).key).toBe(147); expect(treeGrid.getRowByIndex(1).key).toBe(711); @@ -1652,7 +1637,6 @@ describe('IgxTreeGrid - Integration #tGrid', () => { it('should not take into account pinned rows when changing items per page', () => { treeGrid.pinRow(147); - fix.detectChanges(); fix.componentInstance.paging = true; fix.detectChanges(); @@ -1676,8 +1660,6 @@ describe('IgxTreeGrid - Integration #tGrid', () => { const paginator = fix.debugElement.query(By.directive(IgxPaginatorComponent)).componentInstance; // pin the first row treeGrid.getRowByIndex(0).pin(); - fix.detectChanges(); - expect(treeGrid.rowList.length).toEqual(4); expect(treeGrid.perPage).toEqual(3); expect(paginator.perPage).toEqual(3); @@ -1686,7 +1668,6 @@ describe('IgxTreeGrid - Integration #tGrid', () => { // pin the second row treeGrid.getRowByIndex(2).pin(); - fix.detectChanges(); expect(treeGrid.rowList.length).toEqual(5); expect(treeGrid.perPage).toEqual(3); @@ -1702,8 +1683,6 @@ describe('IgxTreeGrid - Integration #tGrid', () => { treeGrid.height = '700px'; fix.detectChanges(); treeGrid.getRowByIndex(0).pin(); - treeGrid.getRowByIndex(1).pin(); - fix.detectChanges(); let rows = treeGrid.rowList.toArray(); @@ -1719,7 +1698,6 @@ describe('IgxTreeGrid - Integration #tGrid', () => { it('should make a correct selection', () => { treeGrid.pinRow(147); - fix.detectChanges(); const range = { rowStart: 0, rowEnd: 2, columnStart: 'ID', columnEnd: 'Name' }; treeGrid.selectRange(range); @@ -1735,7 +1713,6 @@ describe('IgxTreeGrid - Integration #tGrid', () => { it('should remove the pinned chip for filtered out parent', () => { treeGrid.pinRow(147); - fix.detectChanges(); treeGrid.filter('ID', 957, IgxStringFilteringOperand.instance().condition('contains'), false); fix.detectChanges(); From c2c18d79001a0693a629c502c1ec0b63b8e18257 Mon Sep 17 00:00:00 2001 From: Hristo Anastasov Date: Tue, 5 Oct 2021 15:21:01 +0300 Subject: [PATCH 11/36] chore(*): fix lint error, change let with const --- .../src/lib/grids/grid/grid-row-pinning.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/projects/igniteui-angular/src/lib/grids/grid/grid-row-pinning.spec.ts b/projects/igniteui-angular/src/lib/grids/grid/grid-row-pinning.spec.ts index 434a0356c35..6b1aaf11af2 100644 --- a/projects/igniteui-angular/src/lib/grids/grid/grid-row-pinning.spec.ts +++ b/projects/igniteui-angular/src/lib/grids/grid/grid-row-pinning.spec.ts @@ -178,7 +178,7 @@ describe('Row Pinning #grid', () => { it('should emit rowPinned on pin/unpin.', () => { spyOn(grid.rowPinned, 'emit').and.callThrough(); - let row = grid.getRowByIndex(0); + const row = grid.getRowByIndex(0); const rowID = row.key; row.pin(); From 1ee4affe700a761243cccaa32a60d1e3e32ef8fb Mon Sep 17 00:00:00 2001 From: dobromirts Date: Wed, 6 Oct 2021 13:21:43 +0300 Subject: [PATCH 12/36] fix(hierarchical-grid): add correct check for row and expansion indexes --- .../src/lib/grids/grid-base.directive.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/projects/igniteui-angular/src/lib/grids/grid-base.directive.ts b/projects/igniteui-angular/src/lib/grids/grid-base.directive.ts index b4012b0e432..40120a4a876 100644 --- a/projects/igniteui-angular/src/lib/grids/grid-base.directive.ts +++ b/projects/igniteui-angular/src/lib/grids/grid-base.directive.ts @@ -6865,14 +6865,19 @@ export abstract class IgxGridBaseDirective extends DisplayDensityBase implements const activeEl = this.selectionService.activeElement; if (this.nativeElement.tagName.toLowerCase() === 'igx-hierarchical-grid') { - const expansionRowIndexes = Array.from(this.expansionStates.keys()); + const expansionRowIndexes = []; + for (const [key, value] of this.expansionStates.entries()) { + if (value) { + expansionRowIndexes.push(key); + } + } if (this.selectionService.selection.size > 0) { if (expansionRowIndexes.length > 0) { for (const [key, value] of this.selectionService.selection.entries()) { let updatedKey = key; expansionRowIndexes.forEach(row => { let rowIndex; - if (row.ID) { + if (!isNaN(row.ID)) { rowIndex = Number(row.ID); }else { rowIndex = Number(row); From 21a28ac2027e4ffb4583355de9ba87fce57d4b7c Mon Sep 17 00:00:00 2001 From: igdmdimitrov Date: Wed, 6 Oct 2021 14:21:58 +0300 Subject: [PATCH 13/36] chore(*): removed optional decorators --- .../src/lib/grids/toolbar/grid-toolbar-exporter.component.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/projects/igniteui-angular/src/lib/grids/toolbar/grid-toolbar-exporter.component.ts b/projects/igniteui-angular/src/lib/grids/toolbar/grid-toolbar-exporter.component.ts index 381f6b50ea7..7b3b55d1f75 100644 --- a/projects/igniteui-angular/src/lib/grids/toolbar/grid-toolbar-exporter.component.ts +++ b/projects/igniteui-angular/src/lib/grids/toolbar/grid-toolbar-exporter.component.ts @@ -108,8 +108,8 @@ export class IgxGridToolbarExporterComponent extends BaseToolbarDirective { constructor( @Host() protected toolbar: IgxGridToolbarComponent, - @Optional() private excelExporter: IgxExcelExporterService, - @Optional() private csvExporter: IgxCsvExporterService, + private excelExporter: IgxExcelExporterService, + private csvExporter: IgxCsvExporterService, ) { super(toolbar); } From 95bd015cc6fa2a5cab14a02570fbfaf6983d2125 Mon Sep 17 00:00:00 2001 From: VDyulgerov Date: Wed, 6 Oct 2021 15:19:01 +0300 Subject: [PATCH 14/36] fix(grid): add index to pinRow function --- projects/igniteui-angular/src/lib/grids/grid-public-row.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/projects/igniteui-angular/src/lib/grids/grid-public-row.ts b/projects/igniteui-angular/src/lib/grids/grid-public-row.ts index d7ed99a7f71..7f1a38f7fb6 100644 --- a/projects/igniteui-angular/src/lib/grids/grid-public-row.ts +++ b/projects/igniteui-angular/src/lib/grids/grid-public-row.ts @@ -211,7 +211,7 @@ abstract class BaseRow implements RowType { * ``` */ public pin(): boolean { - return this.grid.pinRow(this.key); + return this.grid.pinRow(this.key, this.index); } /** From 83e62a91de3a6fa762c559486b47540895bebba3 Mon Sep 17 00:00:00 2001 From: VDyulgerov Date: Wed, 6 Oct 2021 17:00:14 +0300 Subject: [PATCH 15/36] chore(*): comment an expect test --- .../src/lib/grids/grid/grid-row-pinning.spec.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/projects/igniteui-angular/src/lib/grids/grid/grid-row-pinning.spec.ts b/projects/igniteui-angular/src/lib/grids/grid/grid-row-pinning.spec.ts index 6b1aaf11af2..8587c244e0e 100644 --- a/projects/igniteui-angular/src/lib/grids/grid/grid-row-pinning.spec.ts +++ b/projects/igniteui-angular/src/lib/grids/grid/grid-row-pinning.spec.ts @@ -198,12 +198,12 @@ describe('Row Pinning #grid', () => { expect(row.pinned).toBe(false); expect(grid.rowPinned.emit).toHaveBeenCalledTimes(2); - expect(grid.rowPinned.emit).toHaveBeenCalledWith({ - rowID, - insertAtIndex: 0, - isPinned: false, - row - }); + // expect(grid.rowPinned.emit).toHaveBeenCalledWith({ + // rowID, + // insertAtIndex: 0, + // isPinned: false, + // row + // }); }); it('should pin/unpin via grid API methods.', () => { From 42420a4dd337127c835653ac3d15db88a707676c Mon Sep 17 00:00:00 2001 From: VDyulgerov Date: Thu, 7 Oct 2021 08:35:40 +0300 Subject: [PATCH 16/36] chore(*): remove commented expect, remove array index --- .../src/lib/grids/grid/grid-row-pinning.spec.ts | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/projects/igniteui-angular/src/lib/grids/grid/grid-row-pinning.spec.ts b/projects/igniteui-angular/src/lib/grids/grid/grid-row-pinning.spec.ts index 8587c244e0e..1ceb5f9dad8 100644 --- a/projects/igniteui-angular/src/lib/grids/grid/grid-row-pinning.spec.ts +++ b/projects/igniteui-angular/src/lib/grids/grid/grid-row-pinning.spec.ts @@ -198,12 +198,6 @@ describe('Row Pinning #grid', () => { expect(row.pinned).toBe(false); expect(grid.rowPinned.emit).toHaveBeenCalledTimes(2); - // expect(grid.rowPinned.emit).toHaveBeenCalledWith({ - // rowID, - // insertAtIndex: 0, - // isPinned: false, - // row - // }); }); it('should pin/unpin via grid API methods.', () => { @@ -617,12 +611,12 @@ describe('Row Pinning #grid', () => { expect(paginator.totalPages).toEqual(3); }); - it('should have the correct records shown for pages with pinned rows', () => { + fit('should have the correct records shown for pages with pinned rows', () => { grid.gridAPI.get_row_by_index(0).pin(); let rows = grid.rowList.toArray(); - [1, 2, 1, 2, 3, 4, 5].forEach((x, index) => expect(rows[index].cells.first.value).toEqual(x)); + [1, 1, 2, 3, 4, 5].forEach((x, index) => expect(rows[index].cells.first.value).toEqual(x)); grid.paginate(2); fix.detectChanges(); From 7c56cfdef312c95796cd60754e46a474fd84024b Mon Sep 17 00:00:00 2001 From: VDyulgerov Date: Thu, 7 Oct 2021 08:38:00 +0300 Subject: [PATCH 17/36] chore(grid): change fit to it --- .../src/lib/grids/grid/grid-row-pinning.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/projects/igniteui-angular/src/lib/grids/grid/grid-row-pinning.spec.ts b/projects/igniteui-angular/src/lib/grids/grid/grid-row-pinning.spec.ts index 1ceb5f9dad8..b3191f761ef 100644 --- a/projects/igniteui-angular/src/lib/grids/grid/grid-row-pinning.spec.ts +++ b/projects/igniteui-angular/src/lib/grids/grid/grid-row-pinning.spec.ts @@ -611,7 +611,7 @@ describe('Row Pinning #grid', () => { expect(paginator.totalPages).toEqual(3); }); - fit('should have the correct records shown for pages with pinned rows', () => { + it('should have the correct records shown for pages with pinned rows', () => { grid.gridAPI.get_row_by_index(0).pin(); let rows = grid.rowList.toArray(); From 210896a9332f4145e3eadf0ec56d292e89564ef1 Mon Sep 17 00:00:00 2001 From: Hristo Date: Thu, 7 Oct 2021 10:00:16 +0300 Subject: [PATCH 18/36] Update projects/igniteui-angular/src/lib/grids/grid-base.directive.ts --- projects/igniteui-angular/src/lib/grids/grid-base.directive.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/projects/igniteui-angular/src/lib/grids/grid-base.directive.ts b/projects/igniteui-angular/src/lib/grids/grid-base.directive.ts index 40120a4a876..23db29246fe 100644 --- a/projects/igniteui-angular/src/lib/grids/grid-base.directive.ts +++ b/projects/igniteui-angular/src/lib/grids/grid-base.directive.ts @@ -6879,7 +6879,7 @@ export abstract class IgxGridBaseDirective extends DisplayDensityBase implements let rowIndex; if (!isNaN(row.ID)) { rowIndex = Number(row.ID); - }else { + } else { rowIndex = Number(row); } From ee0fdf363678ae3952461f14b6d22970556dc50d Mon Sep 17 00:00:00 2001 From: Hristo Date: Thu, 7 Oct 2021 14:40:00 +0300 Subject: [PATCH 19/36] Update src/app/grid-state/grid-state.component.ts --- src/app/grid-state/grid-state.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/grid-state/grid-state.component.ts b/src/app/grid-state/grid-state.component.ts index 5c8570abadb..797b0dcd57a 100644 --- a/src/app/grid-state/grid-state.component.ts +++ b/src/app/grid-state/grid-state.component.ts @@ -91,7 +91,7 @@ export class GridSaveStateComponent implements OnInit, AfterViewInit { groupBy: true, columns: true, expansion: true, - rowPinning: true, + rowPinning: true }; public initialColumns: GridState [] = [ From 2ada0c58a8e8d8d3e1d4756d1d587cd33adb5ca7 Mon Sep 17 00:00:00 2001 From: Hristo Date: Thu, 7 Oct 2021 14:40:09 +0300 Subject: [PATCH 20/36] Update src/app/grid-row-pinning/grid-row-pinning.sample.ts --- src/app/grid-row-pinning/grid-row-pinning.sample.ts | 1 - 1 file changed, 1 deletion(-) 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 fbdcd88c940..f57fd1ea016 100644 --- a/src/app/grid-row-pinning/grid-row-pinning.sample.ts +++ b/src/app/grid-row-pinning/grid-row-pinning.sample.ts @@ -45,7 +45,6 @@ export class GridRowPinningSampleComponent implements OnInit, AfterViewInit { groupBy: true, columns: false, rowPinning: true, - rowPinned: true, pinningConfig: true }; public selectionMode; From c53c662b1adcebe27290935bab5d6233852f51fb Mon Sep 17 00:00:00 2001 From: Hristo Anastasov Date: Thu, 7 Oct 2021 14:55:02 +0300 Subject: [PATCH 21/36] chore(*): update the changelog --- CHANGELOG.md | 6 ++++++ projects/igniteui-angular/src/lib/grids/row.directive.ts | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6182d481ce6..11655e18eb5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ All notable changes for each version of this project will be documented in this file. +## 12.2.1 + +### New Features +- `igxGrid`, `igxHierarchicalGrid`, `igxTreeGrid` + - new `rowPinned` event is emitted after a row is pinned/unpinned and grid has already refreshed its state to represent the pinned/unpinned rows in the DOM. + ## 12.2.0 ### New Features diff --git a/projects/igniteui-angular/src/lib/grids/row.directive.ts b/projects/igniteui-angular/src/lib/grids/row.directive.ts index b9d7d50491e..525ff749bd1 100644 --- a/projects/igniteui-angular/src/lib/grids/row.directive.ts +++ b/projects/igniteui-angular/src/lib/grids/row.directive.ts @@ -500,7 +500,7 @@ export class IgxRowDirective implemen /** * Pins the specified row. - * This method emits `rowPinning` event. + * This method emits `rowPinning`\`rowPinned` event. * * ```typescript * // pin the selected row from the grid @@ -513,7 +513,7 @@ export class IgxRowDirective implemen /** * Unpins the specified row. - * This method emits `rowPinning` event. + * This method emits `rowPinning`\`rowPinned` event. * * ```typescript * // unpin the selected row from the grid From 5a5a583d2163ae844191cedeb70c51a1f380aaa7 Mon Sep 17 00:00:00 2001 From: igdmdimitrov Date: Thu, 7 Oct 2021 16:37:43 +0300 Subject: [PATCH 22/36] chore(*): updated changelog --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6182d481ce6..23dee2efdc8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ All notable changes for each version of this project will be documented in this file. +## 13.0.0 + +### New Features +- `IgxCsvExporterService`, `IgxExcelExporterService` + - Exporter services are no longer required to be provided in the application since they are now injected on a root level. + ## 12.2.0 ### New Features From 15c0d62535e32af9c7aae66223d3f084f7c36330 Mon Sep 17 00:00:00 2001 From: dobromirts Date: Thu, 7 Oct 2021 16:46:56 +0300 Subject: [PATCH 23/36] fix(grid): fix getCellByColumn with virtualization #10172 --- .../src/lib/grids/grid-navigation.service.ts | 9 +++++++-- .../src/lib/grids/grid/grid.component.ts | 12 ++++++++++-- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/projects/igniteui-angular/src/lib/grids/grid-navigation.service.ts b/projects/igniteui-angular/src/lib/grids/grid-navigation.service.ts index a6747d11b89..5e2671a8249 100644 --- a/projects/igniteui-angular/src/lib/grids/grid-navigation.service.ts +++ b/projects/igniteui-angular/src/lib/grids/grid-navigation.service.ts @@ -251,10 +251,15 @@ export class IgxGridNavigationService { } public isDataRow(rowIndex: number, includeSummary = false) { + let curRow: any; if (rowIndex < 0 || rowIndex > this.grid.dataView.length - 1) { - return false; + curRow = this.grid.dataView[rowIndex - this.grid.virtualizationState.startIndex]; + if (!curRow){ + return false; + } + } else { + curRow = this.grid.dataView[rowIndex]; } - const curRow = this.grid.dataView[rowIndex]; return curRow && !this.grid.isGroupByRecord(curRow) && !this.grid.isDetailRecord(curRow) && !curRow.childGridsData && (includeSummary || !curRow.summaries); } diff --git a/projects/igniteui-angular/src/lib/grids/grid/grid.component.ts b/projects/igniteui-angular/src/lib/grids/grid/grid.component.ts index c2abddd55b4..0e473e54b55 100644 --- a/projects/igniteui-angular/src/lib/grids/grid/grid.component.ts +++ b/projects/igniteui-angular/src/lib/grids/grid/grid.component.ts @@ -1029,7 +1029,7 @@ export class IgxGridComponent extends IgxGridBaseDirective implements GridType, * @param index */ public getRowByIndex(index: number): RowType { - if (index < 0 || index >= this.dataView.length) { + if (index < 0) { return undefined; } return this.createRow(index); @@ -1140,8 +1140,16 @@ export class IgxGridComponent extends IgxGridBaseDirective implements GridType, */ public createRow(index: number, data?: any): RowType { let row: RowType; + let rec: any; - const rec: any = data ?? this.dataView[index]; + if (index < 0 || index >= this.dataView.length) { + if (index >= this.dataView.length){ + const virtIndex = index - this.gridAPI.grid.virtualizationState.startIndex; + rec = data ?? this.dataView[virtIndex]; + } + }else { + rec = data ?? this.dataView[index]; + } if (rec && this.isGroupByRecord(rec)) { row = new IgxGroupByRow(this, index, rec); From da16344aea23b8d0c465f42976c282ac93289e15 Mon Sep 17 00:00:00 2001 From: Konstantin Dinev Date: Fri, 8 Oct 2021 12:36:33 +0300 Subject: [PATCH 24/36] fix(checkbox, switch): formgroup.reset() isn't working (#10249) * fix(checkbox, switch): form.reset() fix #10214 * test(switch, checkbox): adding form group #10214 * fix(*): no longer use ngModel in grid cb #10214 * chore(*): addressing review comment --- .../lib/checkbox/checkbox.component.spec.ts | 38 ++++++++++++++++--- .../src/lib/checkbox/checkbox.component.ts | 4 +- .../src/lib/grids/cell.component.html | 5 +-- .../src/lib/switch/switch.component.spec.ts | 36 ++++++++++++++++-- .../src/lib/switch/switch.component.ts | 4 +- src/app/input/input.sample.html | 8 ++++ src/app/input/input.sample.ts | 8 ++++ 7 files changed, 84 insertions(+), 19 deletions(-) diff --git a/projects/igniteui-angular/src/lib/checkbox/checkbox.component.spec.ts b/projects/igniteui-angular/src/lib/checkbox/checkbox.component.spec.ts index 94ab36f1cb4..b53ac98a3e5 100644 --- a/projects/igniteui-angular/src/lib/checkbox/checkbox.component.spec.ts +++ b/projects/igniteui-angular/src/lib/checkbox/checkbox.component.spec.ts @@ -1,6 +1,6 @@ import { Component, ViewChild } from '@angular/core'; import { fakeAsync, TestBed, tick, waitForAsync } from '@angular/core/testing'; -import { FormsModule } from '@angular/forms'; +import { FormBuilder, FormsModule, ReactiveFormsModule } from '@angular/forms'; import { By } from '@angular/platform-browser'; import { IgxRippleModule } from '../directives/ripple/ripple.directive'; import { IgxCheckboxComponent } from './checkbox.component'; @@ -22,9 +22,10 @@ describe('IgxCheckbox', () => { CheckboxExternalLabelComponent, CheckboxInvisibleLabelComponent, CheckboxDisabledTransitionsComponent, + CheckboxFormGroupComponent, IgxCheckboxComponent ], - imports: [FormsModule, IgxRippleModule, NoopAnimationsModule] + imports: [FormsModule, ReactiveFormsModule, IgxRippleModule, NoopAnimationsModule] }) .compileComponents(); })); @@ -34,7 +35,7 @@ describe('IgxCheckbox', () => { fixture.detectChanges(); const checkbox = fixture.componentInstance.cb; - const nativeCheckbox = fixture.debugElement.query(By.css('input')).nativeElement; + const nativeCheckbox = checkbox.nativeCheckbox.nativeElement; const nativeLabel = checkbox.nativeLabel.nativeElement; const placeholderLabel = fixture.debugElement.query(By.css('.igx-checkbox__label')).nativeElement; @@ -69,7 +70,7 @@ describe('IgxCheckbox', () => { fixture.detectChanges(); expect(nativeCheckbox.checked).toBe(false); - expect(checkboxInstance.checked).toBe(false); + expect(checkboxInstance.checked).toBe(null); testInstance.subscribed = true; checkboxInstance.name = 'my-checkbox'; @@ -85,6 +86,22 @@ describe('IgxCheckbox', () => { expect(checkboxInstance.name).toEqual('my-checkbox'); })); + it('Initializes with form group', () => { + const fixture = TestBed.createComponent(CheckboxFormGroupComponent); + fixture.detectChanges(); + + const testInstance = fixture.componentInstance; + const checkboxInstance = testInstance.cb; + const form = testInstance.myForm; + + form.setValue({ checkbox: true }); + expect(checkboxInstance.checked).toBe(true); + + form.reset(); + + expect(checkboxInstance.checked).toBe(null); + }); + it('Initializes with external label', () => { const fixture = TestBed.createComponent(CheckboxExternalLabelComponent); const checkboxInstance = fixture.componentInstance.cb; @@ -197,7 +214,7 @@ describe('IgxCheckbox', () => { fixture.detectChanges(); // Should not update - expect(checkboxInstance.checked).toBe(false); + expect(checkboxInstance.checked).toBe(null); expect(testInstance.subscribed).toBe(false); }); @@ -398,3 +415,14 @@ class CheckboxInvisibleLabelComponent { class CheckboxDisabledTransitionsComponent { @ViewChild('cb', { static: true }) public cb: IgxCheckboxComponent; } + +@Component({ + template: `
Form Group
` +}) +class CheckboxFormGroupComponent { + @ViewChild('cb', { static: true }) public cb: IgxCheckboxComponent; + + public myForm = this.fb.group({ checkbox: [''] }); + + constructor(private fb: FormBuilder) {} +} diff --git a/projects/igniteui-angular/src/lib/checkbox/checkbox.component.ts b/projects/igniteui-angular/src/lib/checkbox/checkbox.component.ts index 1ac0423d94c..38b44020c5a 100644 --- a/projects/igniteui-angular/src/lib/checkbox/checkbox.component.ts +++ b/projects/igniteui-angular/src/lib/checkbox/checkbox.component.ts @@ -428,9 +428,7 @@ export class IgxCheckboxComponent implements ControlValueAccessor, EditorProvide /** @hidden @internal */ public writeValue(value: boolean) { - if (typeof value === 'boolean') { - this._checked = value; - } + this._checked = value; } /** @hidden @internal */ diff --git a/projects/igniteui-angular/src/lib/grids/cell.component.html b/projects/igniteui-angular/src/lib/grids/cell.component.html index c87188c2fd2..a731932ca9d 100644 --- a/projects/igniteui-angular/src/lib/grids/cell.component.html +++ b/projects/igniteui-angular/src/lib/grids/cell.component.html @@ -91,12 +91,9 @@ - diff --git a/projects/igniteui-angular/src/lib/switch/switch.component.spec.ts b/projects/igniteui-angular/src/lib/switch/switch.component.spec.ts index 2b6fe131bc3..faaf9217c65 100644 --- a/projects/igniteui-angular/src/lib/switch/switch.component.spec.ts +++ b/projects/igniteui-angular/src/lib/switch/switch.component.spec.ts @@ -1,6 +1,6 @@ import { Component, ViewChild } from '@angular/core'; import { TestBed, waitForAsync } from '@angular/core/testing'; -import { FormsModule } from '@angular/forms'; +import { FormBuilder, FormsModule, ReactiveFormsModule } from '@angular/forms'; import { By } from '@angular/platform-browser'; import { IgxRippleModule } from '../directives/ripple/ripple.directive'; import { IgxSwitchComponent } from './switch.component'; @@ -19,9 +19,10 @@ describe('IgxSwitch', () => { SwitchDisabledComponent, SwitchExternalLabelComponent, SwitchInvisibleLabelComponent, + SwitchFormGroupComponent, IgxSwitchComponent ], - imports: [FormsModule, IgxRippleModule, NoopAnimationsModule] + imports: [FormsModule, ReactiveFormsModule, IgxRippleModule, NoopAnimationsModule] }) .compileComponents(); })); @@ -68,7 +69,7 @@ describe('IgxSwitch', () => { fixture.detectChanges(); expect(nativeCheckbox.checked).toBe(false); - expect(switchInstance.checked).toBe(false); + expect(switchInstance.checked).toBe(null); testInstance.subscribed = true; switchInstance.name = 'my-switch'; @@ -79,6 +80,22 @@ describe('IgxSwitch', () => { expect(switchInstance.name).toEqual('my-switch'); }); + it('Initializes with form group', () => { + const fixture = TestBed.createComponent(SwitchFormGroupComponent); + fixture.detectChanges(); + + const testInstance = fixture.componentInstance; + const switchInstance = testInstance.switch; + const form = testInstance.myForm; + + form.setValue({ switch: true }); + expect(switchInstance.checked).toBe(true); + + form.reset(); + + expect(switchInstance.checked).toBe(null); + }); + it('Initializes with external label', () => { const fixture = TestBed.createComponent(SwitchExternalLabelComponent); const switchInstance = fixture.componentInstance.switch; @@ -149,7 +166,7 @@ describe('IgxSwitch', () => { fixture.detectChanges(); // Should not update - expect(switchInstance.checked).toBe(false); + expect(switchInstance.checked).toBe(null); expect(testInstance.subscribed).toBe(false); }); @@ -256,3 +273,14 @@ class SwitchInvisibleLabelComponent { @ViewChild('switch', { static: true }) public switch: IgxSwitchComponent; public label = 'Invisible Label'; } + +@Component({ + template: `
Form Group
` +}) +class SwitchFormGroupComponent { + @ViewChild('switch', { static: true }) public switch: IgxSwitchComponent; + + public myForm = this.fb.group({ switch: [] }); + + constructor(private fb: FormBuilder) {} +} diff --git a/projects/igniteui-angular/src/lib/switch/switch.component.ts b/projects/igniteui-angular/src/lib/switch/switch.component.ts index 6da66babc5f..bb1a1ff1b27 100644 --- a/projects/igniteui-angular/src/lib/switch/switch.component.ts +++ b/projects/igniteui-angular/src/lib/switch/switch.component.ts @@ -337,9 +337,7 @@ export class IgxSwitchComponent implements ControlValueAccessor, EditorProvider * @internal */ public writeValue(value: boolean) { - if (typeof value === 'boolean') { - this._checked = value; - } + this._checked = value; } /** diff --git a/src/app/input/input.sample.html b/src/app/input/input.sample.html index 52ff8001137..83821f588d9 100644 --- a/src/app/input/input.sample.html +++ b/src/app/input/input.sample.html @@ -122,6 +122,14 @@

Checkbox sample

Brian Vaughan Value + + +
+ Form Group Checkbox + Form Group Switch +
+ +
diff --git a/src/app/input/input.sample.ts b/src/app/input/input.sample.ts index e8525f986f9..ef2bde005d8 100644 --- a/src/app/input/input.sample.ts +++ b/src/app/input/input.sample.ts @@ -1,4 +1,5 @@ import { Component, ChangeDetectionStrategy } from '@angular/core'; +import { FormBuilder } from '@angular/forms'; import { IChangeRadioEventArgs } from 'igniteui-angular'; @Component({ @@ -12,6 +13,11 @@ export class InputSampleComponent { public selected = 'option1'; public airplaneMode = false; + public myForm = this.fb.group({ + checkbox: [], + switch: [] + }); + public user = { comment: '', firstName: 'John', @@ -50,6 +56,8 @@ export class InputSampleComponent { disabled: true }]; + constructor(private fb: FormBuilder) {} + public onClick(event: MouseEvent) { console.log(event); } From d688d5b4594f6893a9b9c7ed0dd5dce0ce005f86 Mon Sep 17 00:00:00 2001 From: igdmdimitrov Date: Mon, 11 Oct 2021 10:27:53 +0300 Subject: [PATCH 25/36] chore(*): fixed filtering tests --- .../src/lib/grids/grid/grid-filtering-ui.spec.ts | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/projects/igniteui-angular/src/lib/grids/grid/grid-filtering-ui.spec.ts b/projects/igniteui-angular/src/lib/grids/grid/grid-filtering-ui.spec.ts index fc20376a5e1..b53b585e91d 100644 --- a/projects/igniteui-angular/src/lib/grids/grid/grid-filtering-ui.spec.ts +++ b/projects/igniteui-angular/src/lib/grids/grid/grid-filtering-ui.spec.ts @@ -487,7 +487,8 @@ describe('IgxGrid - Filtering Row UI actions #grid', () => { expect(grid.filtering.emit).toHaveBeenCalledWith({ owner: grid, cancel: false, filteringExpressions: null }); expect(grid.filtering.emit).toHaveBeenCalledTimes(2); - expect(grid.filteringDone.emit).toHaveBeenCalledWith(null); + const emptyFilter = new FilteringExpressionsTree(null, columnName); + expect(grid.filteringDone.emit).toHaveBeenCalledWith(emptyFilter); expect(grid.filteringDone.emit).toHaveBeenCalledTimes(2); const filterUiRow = fix.debugElement.query(By.css(FILTER_UI_ROW)); @@ -514,7 +515,8 @@ describe('IgxGrid - Filtering Row UI actions #grid', () => { const args = { owner: grid, cancel: false, filteringExpressions: null }; expect(grid.filtering.emit).toHaveBeenCalledWith(args); - expect(grid.filteringDone.emit).toHaveBeenCalledWith(null); + const emptyFilter = new FilteringExpressionsTree(null, columnName); + expect(grid.filteringDone.emit).toHaveBeenCalledWith(emptyFilter); })); it('Removing second condition removes the And/Or button', fakeAsync(() => { @@ -826,13 +828,14 @@ describe('IgxGrid - Filtering Row UI actions #grid', () => { spyOn(grid.filtering, 'emit'); spyOn(grid.filteringDone, 'emit'); - grid.filter('ProductName', 'I', IgxStringFilteringOperand.instance().condition('startsWith')); + const columnName = 'ProductName'; + grid.filter(columnName, 'I', IgxStringFilteringOperand.instance().condition('startsWith')); tick(30); fix.detectChanges(); expect(grid.rowList.length).toEqual(2); - const filteringExpressions = grid.filteringExpressionsTree.find('ProductName') as FilteringExpressionsTree; + const filteringExpressions = grid.filteringExpressionsTree.find(columnName) as FilteringExpressionsTree; const args = { owner: grid, cancel: false, filteringExpressions }; expect(grid.filtering.emit).toHaveBeenCalledWith(args); expect(grid.filtering.emit).toHaveBeenCalledTimes(1); @@ -852,7 +855,8 @@ describe('IgxGrid - Filtering Row UI actions #grid', () => { args.filteringExpressions = null; expect(grid.filtering.emit).toHaveBeenCalledWith(args); expect(grid.filtering.emit).toHaveBeenCalledTimes(2); - expect(grid.filteringDone.emit).toHaveBeenCalledWith(null); + const emptyFilter = new FilteringExpressionsTree(null, columnName); + expect(grid.filteringDone.emit).toHaveBeenCalledWith(emptyFilter); expect(grid.filteringDone.emit).toHaveBeenCalledTimes(2); })); From 7d069c2527142252ce760e66d71dcf654193eb45 Mon Sep 17 00:00:00 2001 From: Plamena Miteva Date: Mon, 11 Oct 2021 10:40:59 +0300 Subject: [PATCH 26/36] fix(overlay): overlay wrapper and element animation should start together #9882 (#10232) --- .../src/lib/dialog/dialog.component.spec.ts | 2 +- .../src/lib/services/overlay/overlay.spec.ts | 193 +++++++++--------- .../src/lib/services/overlay/overlay.ts | 21 +- src/app/overlay/overlay.sample.html | 4 + src/app/overlay/overlay.sample.ts | 8 +- 5 files changed, 127 insertions(+), 101 deletions(-) diff --git a/projects/igniteui-angular/src/lib/dialog/dialog.component.spec.ts b/projects/igniteui-angular/src/lib/dialog/dialog.component.spec.ts index e6e6d196f5f..7e393815e81 100644 --- a/projects/igniteui-angular/src/lib/dialog/dialog.component.spec.ts +++ b/projects/igniteui-angular/src/lib/dialog/dialog.component.spec.ts @@ -345,7 +345,7 @@ describe('Dialog', () => { fix.detectChanges(); dialog.open(); - tick(); + tick(16); fix.detectChanges(); overlaydiv = document.getElementsByClassName(OVERLAY_MAIN_CLASS)[0]; diff --git a/projects/igniteui-angular/src/lib/services/overlay/overlay.spec.ts b/projects/igniteui-angular/src/lib/services/overlay/overlay.spec.ts index b051f22f9c3..e77bb2c38db 100644 --- a/projects/igniteui-angular/src/lib/services/overlay/overlay.spec.ts +++ b/projects/igniteui-angular/src/lib/services/overlay/overlay.spec.ts @@ -51,6 +51,7 @@ const CLASS_OVERLAY_WRAPPER_MODAL = 'igx-overlay__wrapper--modal'; const CLASS_OVERLAY_WRAPPER_FLEX = 'igx-overlay__wrapper--flex'; const CLASS_OVERLAY_MAIN = 'igx-overlay'; const CLASS_SCROLLABLE_DIV = 'scrollableDiv'; +const DEBOUNCE_TIME = 16; // Utility function to get all applied to element css from all sources. const css = (element) => { @@ -258,19 +259,19 @@ describe('igxOverlay', () => { mockFactoryResolver = { resolveComponentFactory: () => ({ create: () => ({ - hostView: '', - location: mockElementRef, - changeDetectorRef: { detectChanges: () => { } }, - destroy: () => { } - }) + hostView: '', + location: mockElementRef, + changeDetectorRef: { detectChanges: () => { } }, + destroy: () => { } }) + }) }; mockApplicationRef = { attachView: () => { }, detachView: () => { } }; mockInjector = {}; mockAnimationBuilder = {}; mockDocument = { body: mockElement, - listeners: { }, + listeners: {}, defaultView: mockElement, // this is used be able to properly invoke rxjs `fromEvent` operator, which, turns out // just adds an event listener to the element and emits accordingly @@ -437,7 +438,7 @@ describe('igxOverlay', () => { fixture.detectChanges(); fixture.componentInstance.buttonElement.nativeElement.click(); - tick(); + tick(DEBOUNCE_TIME); const overlayElement = (fixture.nativeElement as HTMLElement) .parentElement.getElementsByClassName(CLASS_OVERLAY_MAIN)[0] as HTMLElement; @@ -634,8 +635,8 @@ describe('igxOverlay', () => { const bottom = 200; const mockElement = document.createElement('div'); spyOn(mockElement, 'getBoundingClientRect').and.callFake(() => ({ - left, top, width, height, right, bottom - } as DOMRect)); + left, top, width, height, right, bottom + } as DOMRect)); const mockItem = document.createElement('div'); mockElement.append(mockItem); @@ -833,7 +834,7 @@ describe('igxOverlay', () => { SimpleDynamicComponent, { positionStrategy: new ConnectedPositioningStrategy({ target: buttonElement }) }); overlayInstance.show(id); - tick(); + tick(DEBOUNCE_TIME); let contentElement = (fixture.nativeElement as HTMLElement) .parentElement.getElementsByClassName(CLASS_OVERLAY_CONTENT_MODAL)[0] as HTMLElement; @@ -849,7 +850,7 @@ describe('igxOverlay', () => { getPointSpy.and.callThrough().and.returnValue(rect); window.resizeBy(200, 200); window.dispatchEvent(new Event('resize')); - tick(); + tick(DEBOUNCE_TIME); contentElement = (fixture.nativeElement as HTMLElement) .parentElement.getElementsByClassName(CLASS_OVERLAY_CONTENT_MODAL)[0] as HTMLElement; @@ -869,7 +870,7 @@ describe('igxOverlay', () => { // remove SimpleRefComponent HTML element from the DOM tree fixture.elementRef.nativeElement.parentElement.removeChild(fixture.elementRef.nativeElement); overlay.show(overlay.attach(fixture.elementRef)); - tick(); + tick(DEBOUNCE_TIME); const componentElement = fixture.nativeElement as HTMLElement; expect(componentElement).toBeDefined(); @@ -1390,7 +1391,7 @@ describe('igxOverlay', () => { fixture.detectChanges(); fixture.componentInstance.buttonElement.nativeElement.click(); - tick(); + tick(DEBOUNCE_TIME); fixture.detectChanges(); const wrapperElement = (fixture.nativeElement as HTMLElement) @@ -1488,7 +1489,7 @@ describe('igxOverlay', () => { overlay.show(overlay.attach(SimpleDynamicComponent)); overlay.show(overlay.attach(SimpleDynamicComponent)); - tick(); + tick(DEBOUNCE_TIME); const wrapperElements = (fixture.nativeElement as HTMLElement) .parentElement.getElementsByClassName(CLASS_OVERLAY_WRAPPER_MODAL) as HTMLCollectionOf; const wrapperElement1 = wrapperElements[0]; @@ -1532,7 +1533,7 @@ describe('igxOverlay', () => { const overlay = fixture.componentInstance.overlay; overlay.show(overlay.attach(SimpleDynamicComponent)); - tick(); + tick(DEBOUNCE_TIME); fixture.detectChanges(); // overlay container IS NOT a child of the debugElement (attached to body, not app-root) @@ -1660,67 +1661,71 @@ describe('igxOverlay', () => { }); // adding more than one component to show in igx-overlay: - it('Should render the component exactly on top of the previous one when adding a new instance with default settings.', () => { - const fixture = TestBed.createComponent(TopLeftOffsetComponent); - const overlay = fixture.componentInstance.overlay; - const overlaySettings: OverlaySettings = { - positionStrategy: new ConnectedPositioningStrategy() - }; - overlay.show(overlay.attach(SimpleDynamicComponent, overlaySettings)); - overlay.show(overlay.attach(SimpleDynamicComponent, overlaySettings)); - fixture.detectChanges(); + it('Should render the component exactly on top of the previous one when adding a new instance with default settings.', + fakeAsync(() => { + const fixture = TestBed.createComponent(TopLeftOffsetComponent); + const overlay = fixture.componentInstance.overlay; + const overlaySettings: OverlaySettings = { + positionStrategy: new ConnectedPositioningStrategy() + }; + overlay.show(overlay.attach(SimpleDynamicComponent, overlaySettings)); + overlay.show(overlay.attach(SimpleDynamicComponent, overlaySettings)); + tick(DEBOUNCE_TIME); + fixture.detectChanges(); - const wrapperElements = (fixture.nativeElement as HTMLElement) - .parentElement.getElementsByClassName(CLASS_OVERLAY_WRAPPER_MODAL) as HTMLCollectionOf; - const wrapperElement1 = wrapperElements[0]; - const wrapperElement2 = wrapperElements[1]; - const componentElement1 = wrapperElement1.getElementsByTagName('component')[0] as HTMLElement; - const componentElement2 = wrapperElement2.getElementsByTagName('component')[0] as HTMLElement; - const componentRect1 = componentElement1.getBoundingClientRect(); - const componentRect2 = componentElement2.getBoundingClientRect(); - expect(componentRect1.left).toEqual(0); - expect(componentRect1.left).toEqual(componentRect2.left); - expect(componentRect1.top).toEqual(0); - expect(componentRect1.top).toEqual(componentRect2.top); - expect(componentRect1.width).toEqual(componentRect2.width); - expect(componentRect1.height).toEqual(componentRect2.height); - }); + const wrapperElements = (fixture.nativeElement as HTMLElement) + .parentElement.getElementsByClassName(CLASS_OVERLAY_WRAPPER_MODAL) as HTMLCollectionOf; + const wrapperElement1 = wrapperElements[0]; + const wrapperElement2 = wrapperElements[1]; + const componentElement1 = wrapperElement1.getElementsByTagName('component')[0] as HTMLElement; + const componentElement2 = wrapperElement2.getElementsByTagName('component')[0] as HTMLElement; + const componentRect1 = componentElement1.getBoundingClientRect(); + const componentRect2 = componentElement2.getBoundingClientRect(); + expect(componentRect1.left).toEqual(0); + expect(componentRect1.left).toEqual(componentRect2.left); + expect(componentRect1.top).toEqual(0); + expect(componentRect1.top).toEqual(componentRect2.top); + expect(componentRect1.width).toEqual(componentRect2.width); + expect(componentRect1.height).toEqual(componentRect2.height); + })); - it('Should render the component exactly on top of the previous one when adding a new instance with the same options.', () => { - const fixture = TestBed.createComponent(TopLeftOffsetComponent); - const x = 200; - const y = 300; + it('Should render the component exactly on top of the previous one when adding a new instance with the same options.', + fakeAsync(() => { + const fixture = TestBed.createComponent(TopLeftOffsetComponent); + const x = 200; + const y = 300; - const overlay = fixture.componentInstance.overlay; - const positionSettings: PositionSettings = { - horizontalDirection: HorizontalAlignment.Left, - verticalDirection: VerticalAlignment.Top, - horizontalStartPoint: HorizontalAlignment.Left, - verticalStartPoint: VerticalAlignment.Bottom, - }; - const overlaySettings: OverlaySettings = { - target: new Point(x, y), - positionStrategy: new ConnectedPositioningStrategy(positionSettings) - }; - overlay.show(overlay.attach(SimpleDynamicComponent, overlaySettings)); - overlay.show(overlay.attach(SimpleDynamicComponent, overlaySettings)); - fixture.detectChanges(); + const overlay = fixture.componentInstance.overlay; + const positionSettings: PositionSettings = { + horizontalDirection: HorizontalAlignment.Left, + verticalDirection: VerticalAlignment.Top, + horizontalStartPoint: HorizontalAlignment.Left, + verticalStartPoint: VerticalAlignment.Bottom, + }; + const overlaySettings: OverlaySettings = { + target: new Point(x, y), + positionStrategy: new ConnectedPositioningStrategy(positionSettings) + }; + overlay.show(overlay.attach(SimpleDynamicComponent, overlaySettings)); + overlay.show(overlay.attach(SimpleDynamicComponent, overlaySettings)); + tick(DEBOUNCE_TIME); + fixture.detectChanges(); - const wrapperElements = (fixture.nativeElement as HTMLElement) - .parentElement.getElementsByClassName(CLASS_OVERLAY_WRAPPER_MODAL) as HTMLCollectionOf; - const wrapperElement1 = wrapperElements[0]; - const wrapperElement2 = wrapperElements[1]; - const componentElement1 = wrapperElement1.getElementsByTagName('component')[0] as HTMLElement; - const componentElement2 = wrapperElement2.getElementsByTagName('component')[0] as HTMLElement; - const componentRect1 = componentElement1.getBoundingClientRect(); - const componentRect2 = componentElement2.getBoundingClientRect(); - expect(componentRect1.left).toEqual(x - componentRect1.width); - expect(componentRect1.left).toEqual(componentRect2.left); - expect(componentRect1.top).toEqual(y - componentRect1.height); - expect(componentRect1.top).toEqual(componentRect2.top); - expect(componentRect1.width).toEqual(componentRect2.width); - expect(componentRect1.height).toEqual(componentRect2.height); - }); + const wrapperElements = (fixture.nativeElement as HTMLElement) + .parentElement.getElementsByClassName(CLASS_OVERLAY_WRAPPER_MODAL) as HTMLCollectionOf; + const wrapperElement1 = wrapperElements[0]; + const wrapperElement2 = wrapperElements[1]; + const componentElement1 = wrapperElement1.getElementsByTagName('component')[0] as HTMLElement; + const componentElement2 = wrapperElement2.getElementsByTagName('component')[0] as HTMLElement; + const componentRect1 = componentElement1.getBoundingClientRect(); + const componentRect2 = componentElement2.getBoundingClientRect(); + expect(componentRect1.left).toEqual(x - componentRect1.width); + expect(componentRect1.left).toEqual(componentRect2.left); + expect(componentRect1.top).toEqual(y - componentRect1.height); + expect(componentRect1.top).toEqual(componentRect2.top); + expect(componentRect1.width).toEqual(componentRect2.width); + expect(componentRect1.height).toEqual(componentRect2.height); + })); it(`Should change the state of the component to closed when reaching threshold and closing scroll strategy is used.`, fakeAsync(() => { @@ -3010,7 +3015,7 @@ describe('igxOverlay', () => { }; overlay.show(overlay.attach(SimpleDynamicComponent, overlaySettings)); - tick(); + tick(DEBOUNCE_TIME); let wrapperElement = (fixture.nativeElement as HTMLElement) .parentElement.getElementsByClassName(CLASS_OVERLAY_WRAPPER_MODAL)[0] as HTMLElement; @@ -3020,7 +3025,7 @@ describe('igxOverlay', () => { tick(); wrapperElement = (fixture.nativeElement as HTMLElement) - .parentElement.getElementsByClassName(CLASS_OVERLAY_WRAPPER_MODAL)[0] as HTMLElement; + .parentElement.getElementsByClassName(CLASS_OVERLAY_WRAPPER)[0] as HTMLElement; expect(wrapperElement.style.visibility).toEqual('hidden'); })); @@ -3032,14 +3037,14 @@ describe('igxOverlay', () => { }; overlay.show(overlay.attach(SimpleDynamicComponent, overlaySettings)); - tick(); + tick(DEBOUNCE_TIME); let wrapperElement = (fixture.nativeElement as HTMLElement) .parentElement.getElementsByClassName(CLASS_OVERLAY_WRAPPER_MODAL)[0] as HTMLElement; expect(wrapperElement.style.visibility).toEqual(''); UIInteractions.triggerKeyDownEvtUponElem('Escape', document); - tick(); + tick(DEBOUNCE_TIME); wrapperElement = (fixture.nativeElement as HTMLElement) .parentElement.getElementsByClassName(CLASS_OVERLAY_WRAPPER_MODAL)[0] as HTMLElement; @@ -3110,26 +3115,26 @@ describe('igxOverlay', () => { }; overlay.show(overlay.attach(SimpleDynamicComponent, overlaySettings)); - tick(); + tick(DEBOUNCE_TIME); let wrapperElement = (fixture.nativeElement as HTMLElement) .parentElement.getElementsByClassName(CLASS_OVERLAY_WRAPPER_MODAL)[0] as HTMLElement; expect(wrapperElement.style.visibility).toEqual(''); UIInteractions.triggerKeyDownEvtUponElem('Enter', document); - tick(); + tick(DEBOUNCE_TIME); wrapperElement = (fixture.nativeElement as HTMLElement) .parentElement.getElementsByClassName(CLASS_OVERLAY_WRAPPER_MODAL)[0] as HTMLElement; expect(wrapperElement.style.visibility).toEqual(''); UIInteractions.triggerKeyDownEvtUponElem('a', document); - tick(); + tick(DEBOUNCE_TIME); wrapperElement = (fixture.nativeElement as HTMLElement) .parentElement.getElementsByClassName(CLASS_OVERLAY_WRAPPER_MODAL)[0] as HTMLElement; expect(wrapperElement.style.visibility).toEqual(''); UIInteractions.triggerKeyDownEvtUponElem('ArrowUp', document); - tick(); + tick(DEBOUNCE_TIME); wrapperElement = (fixture.nativeElement as HTMLElement) .parentElement.getElementsByClassName(CLASS_OVERLAY_WRAPPER_MODAL)[0] as HTMLElement; expect(wrapperElement.style.visibility).toEqual(''); @@ -3137,7 +3142,7 @@ describe('igxOverlay', () => { UIInteractions.triggerKeyDownEvtUponElem('Escape', document); tick(); wrapperElement = (fixture.nativeElement as HTMLElement) - .parentElement.getElementsByClassName(CLASS_OVERLAY_WRAPPER_MODAL)[0] as HTMLElement; + .parentElement.getElementsByClassName(CLASS_OVERLAY_WRAPPER)[0] as HTMLElement; expect(wrapperElement.style.visibility).toEqual('hidden'); })); @@ -3206,7 +3211,7 @@ describe('igxOverlay', () => { expect(fixture.componentInstance.customComponent.nativeElement.getBoundingClientRect().height).toEqual(280); fixture.componentInstance.buttonElement.nativeElement.click(); tick(); - const componentElement =(fixture.nativeElement as HTMLElement) + const componentElement = (fixture.nativeElement as HTMLElement) .parentElement.getElementsByClassName('customList')[0] as HTMLElement; expect(componentElement).toBeDefined(); expect(componentElement.style.width).toEqual('100%'); @@ -4019,12 +4024,12 @@ describe('igxOverlay', () => { expect(overlay.closing.emit).toHaveBeenCalledTimes(1); expect(overlay.closed.emit).toHaveBeenCalledTimes(1); expect(overlay.closing.emit) - .toHaveBeenCalledWith({ - id: callId, - componentRef: jasmine.any(ComponentRef) as any, - cancel: false, - event: undefined - }); + .toHaveBeenCalledWith({ + id: callId, + componentRef: jasmine.any(ComponentRef) as any, + cancel: false, + event: undefined + }); overlay.detachAll(); overlaySettings.excludeFromOutsideClick = []; @@ -4040,12 +4045,12 @@ describe('igxOverlay', () => { expect(overlay.closing.emit).toHaveBeenCalledTimes(2); expect(overlay.closed.emit).toHaveBeenCalledTimes(2); expect(overlay.closing.emit) - .toHaveBeenCalledWith({ - id: callId, - componentRef: jasmine.any(ComponentRef) as any, - cancel: false, - event: jasmine.any(Event) as any - }); + .toHaveBeenCalledWith({ + id: callId, + componentRef: jasmine.any(ComponentRef) as any, + cancel: false, + event: jasmine.any(Event) as any + }); })); }); diff --git a/projects/igniteui-angular/src/lib/services/overlay/overlay.ts b/projects/igniteui-angular/src/lib/services/overlay/overlay.ts index 36b05b656d6..9c3452f679a 100644 --- a/projects/igniteui-angular/src/lib/services/overlay/overlay.ts +++ b/projects/igniteui-angular/src/lib/services/overlay/overlay.ts @@ -111,7 +111,7 @@ export class IgxOverlayService implements OnDestroy { * } * ``` */ - public contentAppended = new EventEmitter(); + public contentAppended = new EventEmitter(); /** * Emitted just before the overlay animation start. @@ -345,7 +345,6 @@ export class IgxOverlayService implements OnDestroy { this.addOutsideClickListener(info); this.addResizeHandler(); this.addCloseOnEscapeListener(info); - this.addModalClasses(info); this.buildAnimationPlayers(info); return info.id; } @@ -708,6 +707,7 @@ export class IgxOverlayService implements OnDestroy { // to eliminate flickering show the element just before animation start info.wrapperElement.style.visibility = ''; info.visible = true; + this.addModalClasses(info); info.openAnimationPlayer.play(); } @@ -735,6 +735,7 @@ export class IgxOverlayService implements OnDestroy { this.animationStarting.emit({ id: info.id, animationPlayer: info.closeAnimationPlayer, animationType: 'close' }); info.event = event; + this.removeModalClasses(info); info.closeAnimationPlayer.play(); } @@ -883,7 +884,17 @@ export class IgxOverlayService implements OnDestroy { const wrapperElement = info.elementRef.nativeElement.parentElement.parentElement; wrapperElement.classList.remove('igx-overlay__wrapper'); this.applyAnimationParams(wrapperElement, info.settings.positionStrategy.settings.openAnimation); - wrapperElement.classList.add('igx-overlay__wrapper--modal'); + requestAnimationFrame(() => { + wrapperElement.classList.add('igx-overlay__wrapper--modal'); + }); + } + } + + private removeModalClasses(info: OverlayInfo) { + if (info.settings.modal) { + const wrapperElement = info.elementRef.nativeElement.parentElement.parentElement; + wrapperElement.classList.remove('igx-overlay__wrapper--modal'); + wrapperElement.classList.add('igx-overlay__wrapper'); } } @@ -914,7 +925,7 @@ export class IgxOverlayService implements OnDestroy { } } - private openAnimationDone(info: OverlayInfo){ + private openAnimationDone(info: OverlayInfo) { this.opened.emit({ id: info.id, componentRef: info.componentRef }); if (info.openAnimationPlayer) { info.openAnimationPlayer.reset(); @@ -930,7 +941,7 @@ export class IgxOverlayService implements OnDestroy { } } - private closeAnimationDone(info: OverlayInfo){ + private closeAnimationDone(info: OverlayInfo) { this.closeDone(info); if (info.closeAnimationPlayer) { info.closeAnimationPlayer.reset(); diff --git a/src/app/overlay/overlay.sample.html b/src/app/overlay/overlay.sample.html index fe223423e48..8a61cb89f69 100644 --- a/src/app/overlay/overlay.sample.html +++ b/src/app/overlay/overlay.sample.html @@ -70,6 +70,10 @@ + + + +
diff --git a/src/app/overlay/overlay.sample.ts b/src/app/overlay/overlay.sample.ts index 9f4915991c8..92a323848bb 100644 --- a/src/app/overlay/overlay.sample.ts +++ b/src/app/overlay/overlay.sample.ts @@ -11,7 +11,8 @@ import { NoOpScrollStrategy, ElasticPositionStrategy, IgxDragDirective, - ContainerPositionStrategy + ContainerPositionStrategy, + IAnimationParams } from 'igniteui-angular'; @Component({ @@ -48,6 +49,7 @@ export class OverlaySampleComponent implements OnInit { public closeOnOutsideClick = true; public modal = true; public useOutlet = false; + public animationLength = 300; // in ms private xAddition = 0; private yAddition = 0; @@ -341,6 +343,10 @@ export class OverlaySampleComponent implements OnInit { this.cdr.detectChanges(); this.onChange2(); this._overlaySettings.target = this.button.nativeElement; + (this._overlaySettings.positionStrategy.settings.openAnimation.options.params as IAnimationParams).duration + = `${this.animationLength}ms`; + (this._overlaySettings.positionStrategy.settings.closeAnimation.options.params as IAnimationParams).duration + = `${this.animationLength}ms`; } this.igxDropDown.toggle(this._overlaySettings); } From 02d1c77bd761f2bae04e9c3b3437204e136c1194 Mon Sep 17 00:00:00 2001 From: Konstantin Dinev Date: Mon, 11 Oct 2021 11:00:16 +0300 Subject: [PATCH 27/36] chore(*): update cell merging with issue link --- ROADMAP.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ROADMAP.md b/ROADMAP.md index 6187078297f..248ef95c4fe 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -14,7 +14,7 @@ ## Going down the road 1. Angular Pivot Grid [#5700](https://github.com/IgniteUI/igniteui-angular/issues/5700) -2. Grid Cell Merging +2. Grid Cell Merging #3514 3. PDF Export feature on Angular Grid [#5696](https://github.com/IgniteUI/igniteui-angular/issues/5696) 4. Themes: Move code to Sass modules [#9554](https://github.com/IgniteUI/igniteui-angular/issues/9554) 5. Themes: Split themes and aid with Grid refactoring [#9556](https://github.com/IgniteUI/igniteui-angular/issues/9556) From dc629e228bd85ffc50316b6b6fe8ab07e9850d41 Mon Sep 17 00:00:00 2001 From: Konstantin Dinev Date: Mon, 11 Oct 2021 11:00:38 +0300 Subject: [PATCH 28/36] Update ROADMAP.md --- ROADMAP.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ROADMAP.md b/ROADMAP.md index 248ef95c4fe..10171a2cac3 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -14,7 +14,7 @@ ## Going down the road 1. Angular Pivot Grid [#5700](https://github.com/IgniteUI/igniteui-angular/issues/5700) -2. Grid Cell Merging #3514 +2. Grid Cell Merging [#3514](https://github.com/IgniteUI/igniteui-angular/issues/3514) 3. PDF Export feature on Angular Grid [#5696](https://github.com/IgniteUI/igniteui-angular/issues/5696) 4. Themes: Move code to Sass modules [#9554](https://github.com/IgniteUI/igniteui-angular/issues/9554) 5. Themes: Split themes and aid with Grid refactoring [#9556](https://github.com/IgniteUI/igniteui-angular/issues/9556) From c1bdc458c3ed73bd7b0ae7e307ce772c655c8f7b Mon Sep 17 00:00:00 2001 From: igdmdimitrov Date: Mon, 11 Oct 2021 13:20:04 +0300 Subject: [PATCH 29/36] fix(esf): add empty filter to filtering event --- .../lib/grids/filtering/grid-filtering.service.ts | 4 ++-- .../src/lib/grids/grid/grid-filtering-ui.spec.ts | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/projects/igniteui-angular/src/lib/grids/filtering/grid-filtering.service.ts b/projects/igniteui-angular/src/lib/grids/filtering/grid-filtering.service.ts index 209e73f7b36..fbe64f992a1 100644 --- a/projects/igniteui-angular/src/lib/grids/filtering/grid-filtering.service.ts +++ b/projects/igniteui-angular/src/lib/grids/filtering/grid-filtering.service.ts @@ -277,9 +277,10 @@ export class IgxFilteringService implements OnDestroy { } } + const emptyFilter = new FilteringExpressionsTree(null, field); const onFilteringEventArgs: IFilteringEventArgs = { owner: this.grid, - filteringExpressions: null, + filteringExpressions: emptyFilter, cancel: false }; this.grid.filtering.emit(onFilteringEventArgs); @@ -292,7 +293,6 @@ export class IgxFilteringService implements OnDestroy { this.clear_filter(field); // Wait for the change detection to update filtered data through the pipes and then emit the event. - const emptyFilter = new FilteringExpressionsTree(null, field); requestAnimationFrame(() => this.grid.filteringDone.emit(emptyFilter)); if (field) { diff --git a/projects/igniteui-angular/src/lib/grids/grid/grid-filtering-ui.spec.ts b/projects/igniteui-angular/src/lib/grids/grid/grid-filtering-ui.spec.ts index b53b585e91d..39ca93a5c88 100644 --- a/projects/igniteui-angular/src/lib/grids/grid/grid-filtering-ui.spec.ts +++ b/projects/igniteui-angular/src/lib/grids/grid/grid-filtering-ui.spec.ts @@ -485,9 +485,9 @@ describe('IgxGrid - Filtering Row UI actions #grid', () => { GridFunctions.clickFilterCellChip(fix, columnName); GridFunctions.resetFilterRow(fix); - expect(grid.filtering.emit).toHaveBeenCalledWith({ owner: grid, cancel: false, filteringExpressions: null }); - expect(grid.filtering.emit).toHaveBeenCalledTimes(2); const emptyFilter = new FilteringExpressionsTree(null, columnName); + expect(grid.filtering.emit).toHaveBeenCalledWith({ owner: grid, cancel: false, filteringExpressions: emptyFilter }); + expect(grid.filtering.emit).toHaveBeenCalledTimes(2); expect(grid.filteringDone.emit).toHaveBeenCalledWith(emptyFilter); expect(grid.filteringDone.emit).toHaveBeenCalledTimes(2); @@ -513,9 +513,9 @@ describe('IgxGrid - Filtering Row UI actions #grid', () => { tick(100); fix.detectChanges(); - const args = { owner: grid, cancel: false, filteringExpressions: null }; - expect(grid.filtering.emit).toHaveBeenCalledWith(args); const emptyFilter = new FilteringExpressionsTree(null, columnName); + const args = { owner: grid, cancel: false, filteringExpressions: emptyFilter }; + expect(grid.filtering.emit).toHaveBeenCalledWith(args); expect(grid.filteringDone.emit).toHaveBeenCalledWith(emptyFilter); })); @@ -852,10 +852,10 @@ describe('IgxGrid - Filtering Row UI actions #grid', () => { expect(grid.rowList.length).toEqual(8); - args.filteringExpressions = null; + const emptyFilter = new FilteringExpressionsTree(null, columnName); + args.filteringExpressions = emptyFilter; expect(grid.filtering.emit).toHaveBeenCalledWith(args); expect(grid.filtering.emit).toHaveBeenCalledTimes(2); - const emptyFilter = new FilteringExpressionsTree(null, columnName); expect(grid.filteringDone.emit).toHaveBeenCalledWith(emptyFilter); expect(grid.filteringDone.emit).toHaveBeenCalledTimes(2); })); From 5348e6702495afe8fc8f00efcdfd351cb63351df Mon Sep 17 00:00:00 2001 From: Konstantin Dinev Date: Mon, 11 Oct 2021 16:37:56 +0300 Subject: [PATCH 30/36] docs(readme): adding app builder links --- README.md | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index a1b26d8ee06..ad12d325d9f 100644 --- a/README.md +++ b/README.md @@ -25,12 +25,10 @@ Ignite UI for Angular arrives with an extensive library of data visualizations t Some of the Angular chart types included are: [Polar chart](https://www.infragistics.com/products/ignite-ui-angular/angular/components/charts/types/polar-chart), [Pie chart](https://www.infragistics.com/products/ignite-ui-angular/angular/components/charts/types/pie-chart), [Donut chart](https://www.infragistics.com/products/ignite-ui-angular/angular/components/charts/types/donut-chart), [Bubble chart](https://www.infragistics.com/products/ignite-ui-angular/angular/components/charts/types/bubble-chart), [Area chart](https://www.infragistics.com/products/ignite-ui-angular/angular/components/charts/types/area-chart), [Treemap chart](https://www.infragistics.com/products/ignite-ui-angular/angular/components/charts/types/treemap-chart), and many others. And if you look for [Angular financial charts](https://www.infragistics.com/products/ignite-ui-angular/angular/components/charts/types/stock-chart), with Ignite UI you can get the same features as the ones you come across with Google Finance and Yahoo Finance Charts. -### [**Install our VSCode Toolbox extension**](https://marketplace.visualstudio.com/items?itemName=Infragistics.igniteui-angular-toolbox) -![](https://dl.infragistics.com/tools/extensions/angular-toolbox/toolbox.gif) -### [**Install our VSCode tooltip extension**](https://marketplace.visualstudio.com/items?itemName=Infragistics.igniteui-angular-tooltips) -![](https://dl.infragistics.com/tools/extensions/angular-tooltips/tooltip_preview.gif) - -**IMPORTANT** The repository has been renamed from `igniteui-js-blocks` to `igniteui-angular`. Read more on our new [naming convention](https://www.infragistics.com/community/blogs/b/infragistics/posts/ignite-ui-github-repo-name-changes). +### Build Apps with Ignite UI for Angular faster using our [App Builder](https://www.infragistics.com/products/indigo-design/app-builder) +![5661 drag drop](https://user-images.githubusercontent.com/1472513/132676597-09eec222-42f7-40ff-bd0d-fe8b91fd0c1c.gif) +### Generate your Angular code projects using the [App Builder](https://www.infragistics.com/products/indigo-design/app-builder) +![0871 change-preview-code](https://user-images.githubusercontent.com/1472513/132676607-3851f308-416b-45d6-99bc-c34266b55c44.gif) ### Current List of Components Include: From 791b9a5fcfb8dd3f696d3c3771cdeea1843d6247 Mon Sep 17 00:00:00 2001 From: Simeon Simeonoff Date: Mon, 11 Oct 2021 17:07:26 +0300 Subject: [PATCH 31/36] refactor(icon-service): cache svg icons as text (#10202) * refactor(icon-service): cache svg icons as text * refactor(icon): return SafeHtml from IconService * spec(icon-service): update * refactor(icon): remove lifecycle hook changes * docs(icon, icon-service): update after changes * docs(icon-service): update * refactor(icon): update template and theme * chore(*): update svg assets * refactor(icon-service): simplify family initialization * spec(icon-service): fix failing test * refactor(advanced-filtering): show friendly name for igx-select text * refactor(excel-filter): use condition friendly name * refactor(icon, icon-service): simplify code * test(grid): dont include the svg icon in the query for dropdown item * refactor(icon, icon service): cache svg icons as SafeHtml * refactor(icon): replace svg wrapper with a div * refactor(demos): add a new test icon * refactor(icon): set svg and div to display block Co-authored-by: Hristo Anastasov Co-authored-by: Hristo --- .../styles/components/icon/_icon-theme.scss | 6 +- .../advanced-filtering-dialog.component.html | 2 +- ...el-style-default-expression.component.html | 2 +- ...xcel-style-default-expression.component.ts | 4 + .../src/lib/icon/icon.component.html | 4 +- .../src/lib/icon/icon.component.ts | 29 ++++--- .../src/lib/icon/icon.service.spec.ts | 35 ++------ .../src/lib/icon/icon.service.ts | 82 +++++-------------- .../src/lib/test-utils/grid-functions.spec.ts | 5 +- src/app/icon/icon.sample.html | 1 + src/app/icon/icon.sample.ts | 1 + src/assets/svg/filtering/contains.svg | 19 +---- src/assets/svg/filtering/copy.svg | 3 + src/assets/svg/filtering/does_not_contain.svg | 21 +---- src/assets/svg/filtering/does_not_equal.svg | 19 +---- src/assets/svg/filtering/ends_with.svg | 19 +---- src/assets/svg/filtering/equals.svg | 19 +---- src/assets/svg/filtering/is_empty.svg | 19 +---- src/assets/svg/filtering/starts_with.svg | 19 +---- 19 files changed, 70 insertions(+), 239 deletions(-) create mode 100644 src/assets/svg/filtering/copy.svg diff --git a/projects/igniteui-angular/src/lib/core/styles/components/icon/_icon-theme.scss b/projects/igniteui-angular/src/lib/core/styles/components/icon/_icon-theme.scss index 5984304189d..00167f8686f 100644 --- a/projects/igniteui-angular/src/lib/core/styles/components/icon/_icon-theme.scss +++ b/projects/igniteui-angular/src/lib/core/styles/components/icon/_icon-theme.scss @@ -64,14 +64,12 @@ font-size: $igx-icon-font-size; color: --var($theme, 'color'); + div, svg { + display: block; width: inherit; height: inherit; fill: currentColor; - - use { - pointer-events: none; - } } } diff --git a/projects/igniteui-angular/src/lib/grids/filtering/advanced-filtering/advanced-filtering-dialog.component.html b/projects/igniteui-angular/src/lib/grids/filtering/advanced-filtering/advanced-filtering-dialog.component.html index 918d4a09464..56b2d61ad00 100644 --- a/projects/igniteui-angular/src/lib/grids/filtering/advanced-filtering/advanced-filtering-dialog.component.html +++ b/projects/igniteui-angular/src/lib/grids/filtering/advanced-filtering/advanced-filtering-dialog.component.html @@ -162,7 +162,7 @@
- +
diff --git a/projects/igniteui-angular/src/lib/grids/filtering/excel-style/excel-style-default-expression.component.html b/projects/igniteui-angular/src/lib/grids/filtering/excel-style/excel-style-default-expression.component.html index 53f40145c0f..ba9f88ac028 100644 --- a/projects/igniteui-angular/src/lib/grids/filtering/excel-style/excel-style-default-expression.component.html +++ b/projects/igniteui-angular/src/lib/grids/filtering/excel-style/excel-style-default-expression.component.html @@ -8,7 +8,7 @@ filter_list - +
{{translateCondition(condition)}} diff --git a/projects/igniteui-angular/src/lib/grids/filtering/excel-style/excel-style-default-expression.component.ts b/projects/igniteui-angular/src/lib/grids/filtering/excel-style/excel-style-default-expression.component.ts index 878b7e8df9a..2a48c59e02a 100644 --- a/projects/igniteui-angular/src/lib/grids/filtering/excel-style/excel-style-default-expression.component.ts +++ b/projects/igniteui-angular/src/lib/grids/filtering/excel-style/excel-style-default-expression.component.ts @@ -155,6 +155,10 @@ export class IgxExcelStyleDefaultExpressionComponent implements AfterViewInit { return this.column.filters.condition(value); } + public getConditionFriendlyName(name: string): string { + return this.grid.resourceStrings[`igx_grid_filter_${name}`] || name; + } + public onValuesInput(eventArgs) { this.expressionUI.expression.searchVal = DataUtil.parseValue(this.column.dataType, eventArgs.target.value); } diff --git a/projects/igniteui-angular/src/lib/icon/icon.component.html b/projects/igniteui-angular/src/lib/icon/icon.component.html index 665287d1806..09a4d7d7cf1 100644 --- a/projects/igniteui-angular/src/lib/icon/icon.component.html +++ b/projects/igniteui-angular/src/lib/icon/icon.component.html @@ -5,9 +5,7 @@ - - - +
diff --git a/projects/igniteui-angular/src/lib/icon/icon.component.ts b/projects/igniteui-angular/src/lib/icon/icon.component.ts index d3354ebb414..b1f83eb65da 100644 --- a/projects/igniteui-angular/src/lib/icon/icon.component.ts +++ b/projects/igniteui-angular/src/lib/icon/icon.component.ts @@ -3,6 +3,7 @@ import { IgxIconService } from './icon.service'; import { first, takeUntil } from 'rxjs/operators'; import { Subject } from 'rxjs'; import { DeprecateProperty } from '../core/deprecateDecorators'; +import { SafeHtml } from '@angular/platform-browser'; /** * Icon provides a way to include material icons to markup @@ -114,16 +115,19 @@ export class IgxIconComponent implements OnInit, OnDestroy { private destroy$ = new Subject(); - constructor(public el: ElementRef, - private iconService: IgxIconService, - private ref: ChangeDetectorRef) { + constructor( + public el: ElementRef, + private iconService: IgxIconService, + private ref: ChangeDetectorRef, + ) { this.family = this.iconService.defaultFamily; this.iconService.registerFamilyAlias('material', 'material-icons'); - this.iconService.iconLoaded.pipe( - first(e => e.name === this.name && e.family === this.family), - takeUntil(this.destroy$) - ) - .subscribe(() => this.ref.detectChanges()); + this.iconService.iconLoaded + .pipe( + first((e) => e.name === this.name && e.family === this.family), + takeUntil(this.destroy$) + ) + .subscribe(() => this.ref.detectChanges()); } /** @@ -226,21 +230,20 @@ export class IgxIconComponent implements OnInit, OnDestroy { } /** - * An accessor that returns the key of the SVG image. - * The key consists of the font-family and the name separated by underscore. + * An accessor that returns the underlying SVG image as SafeHtml. * * @example * ```typescript * @ViewChild("MyIcon") * public icon: IgxIconComponent; * ngAfterViewInit() { - * let svgKey = this.icon.getSvgKey; + * let svg: SafeHtml = this.icon.getSvg; * } * ``` */ - public get getSvgKey(): string { + public get getSvg(): SafeHtml { if (this.iconService.isSvgIconCached(this.name, this.family)) { - return '#' + this.iconService.getSvgIconKey(this.name, this.family); + return this.iconService.getSvgIcon(this.name, this.family); } return null; diff --git a/projects/igniteui-angular/src/lib/icon/icon.service.spec.ts b/projects/igniteui-angular/src/lib/icon/icon.service.spec.ts index 58e667387e7..89e9cdff673 100644 --- a/projects/igniteui-angular/src/lib/icon/icon.service.spec.ts +++ b/projects/igniteui-angular/src/lib/icon/icon.service.spec.ts @@ -1,6 +1,5 @@ -import { TestBed } from '@angular/core/testing'; +import { TestBed, fakeAsync } from '@angular/core/testing'; import { IgxIconService } from './icon.service'; -import { DOCUMENT } from '@angular/common'; import { configureTestSuite } from '../test-utils/configure-suite'; import { first } from 'rxjs/operators'; @@ -53,13 +52,11 @@ describe('Icon Service', () => { expect(iconService.familyClassName(ALIAS)).toBe(MY_FONT); }); - it('should add custom svg icon from url', () => { + it('should add custom svg icon from url', fakeAsync((done) => { const iconService = TestBed.inject(IgxIconService) as IgxIconService; - const document = TestBed.inject(DOCUMENT); const name = 'test'; const family = 'svg-icons'; - const iconKey = family + '_' + name; spyOn(XMLHttpRequest.prototype, 'open').and.callThrough(); spyOn(XMLHttpRequest.prototype, 'send'); @@ -69,25 +66,20 @@ describe('Icon Service', () => { expect(XMLHttpRequest.prototype.open).toHaveBeenCalledTimes(1); expect(XMLHttpRequest.prototype.send).toHaveBeenCalledTimes(1); - const svgElement = document.querySelector(`svg[id='${iconKey}']`); - expect(svgElement).toBeDefined(); - }); + iconService.iconLoaded.pipe().subscribe(() => { + expect(iconService.isSvgIconCached(name, family)).toBeTruthy(); + done(); + }); + })); it('should add custom svg icon from text', () => { const iconService = TestBed.inject(IgxIconService) as IgxIconService; - const document = TestBed.inject(DOCUMENT); const name = 'test'; const family = 'svg-icons'; - const iconKey = family + '_' + name; iconService.addSvgIconFromText(name, svgText, family); - expect(iconService.isSvgIconCached(name, family)).toBeTruthy(); - expect(iconService.getSvgIconKey(name, family)).toEqual(iconKey); - - const svgElement = document.querySelector(`svg[id='${iconKey}']`); - expect(svgElement).toBeDefined(); }); it('should emit loading event for a custom svg icon from url', done => { @@ -113,17 +105,4 @@ describe('Icon Service', () => { iconService.addSvgIcon(name, 'test.svg', family); }); - - it('should create svg container inside the body', () => { - const iconService = TestBed.inject(IgxIconService) as IgxIconService; - const document = TestBed.inject(DOCUMENT); - - const name = 'test'; - const family = 'svg-icons'; - - iconService.addSvgIconFromText(name, svgText, family); - - const svgContainer = document.body.querySelector('.igx-svg-container'); - expect(svgContainer).not.toBeNull(); - }); }); diff --git a/projects/igniteui-angular/src/lib/icon/icon.service.ts b/projects/igniteui-angular/src/lib/icon/icon.service.ts index 12f5e426d6e..ca22d4b463a 100644 --- a/projects/igniteui-angular/src/lib/icon/icon.service.ts +++ b/projects/igniteui-angular/src/lib/icon/icon.service.ts @@ -1,5 +1,5 @@ -import { Injectable, SecurityContext, Inject, OnDestroy, Optional } from '@angular/core'; -import { DomSanitizer } from '@angular/platform-browser'; +import { Injectable, SecurityContext, Inject, Optional } from '@angular/core'; +import { DomSanitizer, SafeHtml } from '@angular/platform-browser'; import { DOCUMENT } from '@angular/common'; import { HttpClient } from '@angular/common/http'; import { Observable, Subject } from 'rxjs'; @@ -32,7 +32,7 @@ export interface IgxIconLoadedEvent { @Injectable({ providedIn: 'root' }) -export class IgxIconService implements OnDestroy { +export class IgxIconService { /** * Observable that emits when an icon is successfully loaded * through a HTTP request. @@ -46,9 +46,9 @@ export class IgxIconService implements OnDestroy { private _family = 'material-icons'; private _familyAliases = new Map(); - private _svgContainer: HTMLElement; - private _cachedSvgIcons: Set = new Set(); + private _cachedSvgIcons = new Map>(); private _iconLoaded = new Subject(); + private _domParser = new DOMParser(); constructor( @Optional() private _sanitizer: DomSanitizer, @@ -58,14 +58,6 @@ export class IgxIconService implements OnDestroy { this.iconLoaded = this._iconLoaded.asObservable(); } - /** - * @hidden - * @internal - */ - public ngOnDestroy(): void { - this.cleanSvgContainer(); - } - /** * Returns the default font-family. * ```typescript @@ -162,18 +154,22 @@ export class IgxIconService implements OnDestroy { * ``` */ public isSvgIconCached(name: string, family: string = ''): boolean { - const iconKey = this.getSvgIconKey(name, family); - return this._cachedSvgIcons.has(iconKey); + if(this._cachedSvgIcons.has(family)) { + const familyRegistry = this._cachedSvgIcons.get(family) as Map; + return familyRegistry.has(name); + } + + return false; } /** - * Returns the key of a cached SVG image. + * Returns the cached SVG image as string. * ```typescript - * const svgIconKey = this.iconService.getSvgIconKey('aruba', 'svg-flags'); + * const svgIcon = this.iconService.getSvgIcon('aruba', 'svg-flags'); * ``` */ - public getSvgIconKey(name: string, family: string = '') { - return family + '_' + name; + public getSvgIcon(name: string, family: string = '') { + return this._cachedSvgIcons.get(family)?.get(name); } /** @@ -184,57 +180,23 @@ export class IgxIconService implements OnDestroy { return req; } - /** - * @hidden - */ - private cleanSvgContainer() { - const container = this._document.documentElement.querySelector('.igx-svg-container'); - - while (container.firstChild) { - container.removeChild(container.firstChild); - } - } - /** * @hidden */ private cacheSvgIcon(name: string, value: string, family: string = '') { if (name && value) { - this.ensureSvgContainerCreated(); + const doc = this._domParser.parseFromString(value, 'image/svg+xml'); + const svg = doc.querySelector('svg') as SVGElement; - const div = this._document.createElement('DIV'); - div.innerHTML = value; - const svg = div.querySelector('svg') as SVGElement; + if (!this._cachedSvgIcons.has(family)) { + this._cachedSvgIcons.set(family, new Map()); + } if (svg) { - const iconKey = this.getSvgIconKey(name, family); - - svg.setAttribute('id', iconKey); svg.setAttribute('fit', ''); svg.setAttribute('preserveAspectRatio', 'xMidYMid meet'); - svg.setAttribute('focusable', 'false'); // Disable IE11 default behavior to make SVGs focusable. - - if (this.isSvgIconCached(name, family)) { - const oldChild = this._svgContainer.querySelector(`svg[id='${iconKey}']`); - this._svgContainer.removeChild(oldChild); - } - - this._svgContainer.appendChild(svg); - this._cachedSvgIcons.add(iconKey); - } - } - } - - /** - * @hidden - */ - private ensureSvgContainerCreated() { - if (!this._svgContainer) { - this._svgContainer = this._document.documentElement.querySelector('.igx-svg-container'); - if (!this._svgContainer) { - this._svgContainer = this._document.createElement('DIV'); - this._svgContainer.classList.add('igx-svg-container'); - this._document.body.appendChild(this._svgContainer); + const safeSvg = this._sanitizer.bypassSecurityTrustHtml(svg.outerHTML); + this._cachedSvgIcons.get(family).set(name, safeSvg); } } } diff --git a/projects/igniteui-angular/src/lib/test-utils/grid-functions.spec.ts b/projects/igniteui-angular/src/lib/test-utils/grid-functions.spec.ts index c822dd4d2d9..35de81a1d9d 100644 --- a/projects/igniteui-angular/src/lib/test-utils/grid-functions.spec.ts +++ b/projects/igniteui-angular/src/lib/test-utils/grid-functions.spec.ts @@ -596,8 +596,9 @@ export class GridFunctions { const ddItems = ddList.nativeElement.children; let i; for (i = 0; i < ddItems.length; i++) { - if (ddItems[i].textContent === cond) { - ddItems[i].click(); + const ddItem = ddItems[i].querySelector('.igx-grid__filtering-dropdown-items span'); + if (ddItem.textContent === cond) { + ddItem.click(); tick(100); return; } diff --git a/src/app/icon/icon.sample.html b/src/app/icon/icon.sample.html index 3babb750cff..625b60acf75 100644 --- a/src/app/icon/icon.sample.html +++ b/src/app/icon/icon.sample.html @@ -86,6 +86,7 @@

Using SVG Icons

+
diff --git a/src/app/icon/icon.sample.ts b/src/app/icon/icon.sample.ts index 0b2174a9d52..341e3427249 100644 --- a/src/app/icon/icon.sample.ts +++ b/src/app/icon/icon.sample.ts @@ -19,5 +19,6 @@ export class IconSampleComponent implements OnInit { this._iconService.addSvgIcon('equals', '/assets/svg/filtering/equals.svg', 'svg-flags'); this._iconService.addSvgIcon('is_empty', '/assets/svg/filtering/is_empty.svg', 'svg-flags'); this._iconService.addSvgIcon('starts_with', '/assets/svg/filtering/starts_with.svg', 'svg-flags'); + this._iconService.addSvgIcon('copy', '/assets/svg/filtering/copy.svg', 'svg-flags'); } } diff --git a/src/assets/svg/filtering/contains.svg b/src/assets/svg/filtering/contains.svg index a69a25741ca..67ca24a7550 100644 --- a/src/assets/svg/filtering/contains.svg +++ b/src/assets/svg/filtering/contains.svg @@ -1,21 +1,4 @@ - - Icons/filter/contains - Created with Sketch. - - - - - - - - - - - - - - - \ No newline at end of file + diff --git a/src/assets/svg/filtering/copy.svg b/src/assets/svg/filtering/copy.svg new file mode 100644 index 00000000000..9837dbd779f --- /dev/null +++ b/src/assets/svg/filtering/copy.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/svg/filtering/does_not_contain.svg b/src/assets/svg/filtering/does_not_contain.svg index 75e0c0a9a2c..ea539ea543e 100644 --- a/src/assets/svg/filtering/does_not_contain.svg +++ b/src/assets/svg/filtering/does_not_contain.svg @@ -1,21 +1,4 @@ - - - Icons/filter/does not contain - Created with Sketch. + - - - - - - - - - - - - - - - \ No newline at end of file + diff --git a/src/assets/svg/filtering/does_not_equal.svg b/src/assets/svg/filtering/does_not_equal.svg index 585f8475ac7..3f45e895704 100644 --- a/src/assets/svg/filtering/does_not_equal.svg +++ b/src/assets/svg/filtering/does_not_equal.svg @@ -1,21 +1,4 @@ - - Icons/filter/does not equal - Created with Sketch. - - - - - - - - - - - - - - - \ No newline at end of file + diff --git a/src/assets/svg/filtering/ends_with.svg b/src/assets/svg/filtering/ends_with.svg index 6e0ce79bf28..eac2e5e66ba 100644 --- a/src/assets/svg/filtering/ends_with.svg +++ b/src/assets/svg/filtering/ends_with.svg @@ -1,21 +1,4 @@ - - Icons/filter/ends with - Created with Sketch. - - - - - - - - - - - - - - - \ No newline at end of file + diff --git a/src/assets/svg/filtering/equals.svg b/src/assets/svg/filtering/equals.svg index 47cf89046e6..6123793ff4b 100644 --- a/src/assets/svg/filtering/equals.svg +++ b/src/assets/svg/filtering/equals.svg @@ -1,21 +1,4 @@ - - Icons/filter/equals - Created with Sketch. - - - - - - - - - - - - - - - \ No newline at end of file + diff --git a/src/assets/svg/filtering/is_empty.svg b/src/assets/svg/filtering/is_empty.svg index dd271bcbbd9..5a8e83cb64b 100644 --- a/src/assets/svg/filtering/is_empty.svg +++ b/src/assets/svg/filtering/is_empty.svg @@ -1,21 +1,4 @@ - - Icons/filter/is empty - Created with Sketch. - - - - - - - - - - - - - - - \ No newline at end of file + diff --git a/src/assets/svg/filtering/starts_with.svg b/src/assets/svg/filtering/starts_with.svg index c5e44e0b699..317824785a2 100644 --- a/src/assets/svg/filtering/starts_with.svg +++ b/src/assets/svg/filtering/starts_with.svg @@ -1,21 +1,4 @@ - - Icons/filter/starts with - Created with Sketch. - - - - - - - - - - - - - - - \ No newline at end of file + From 1e36b869451eec1f08002f8ef6638709d922f192 Mon Sep 17 00:00:00 2001 From: Simeon Simeonoff Date: Mon, 11 Oct 2021 18:25:45 +0300 Subject: [PATCH 32/36] fix(icon-service): can't register icon w/o family --- projects/igniteui-angular/src/lib/icon/icon.service.ts | 10 ++++++---- src/app/icon/icon.sample.html | 2 +- src/app/icon/icon.sample.ts | 2 +- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/projects/igniteui-angular/src/lib/icon/icon.service.ts b/projects/igniteui-angular/src/lib/icon/icon.service.ts index ca22d4b463a..bab19ccea38 100644 --- a/projects/igniteui-angular/src/lib/icon/icon.service.ts +++ b/projects/igniteui-angular/src/lib/icon/icon.service.ts @@ -105,7 +105,7 @@ export class IgxIconService { * this.iconService.addSvgIcon('aruba', '/assets/svg/country_flags/aruba.svg', 'svg-flags'); * ``` */ - public addSvgIcon(name: string, url: string, family: string = '') { + public addSvgIcon(name: string, url: string, family = this._family) { if (name && url) { const safeUrl = this._sanitizer.bypassSecurityTrustResourceUrl(url); if (!safeUrl) { @@ -154,8 +154,9 @@ export class IgxIconService { * ``` */ public isSvgIconCached(name: string, family: string = ''): boolean { - if(this._cachedSvgIcons.has(family)) { - const familyRegistry = this._cachedSvgIcons.get(family) as Map; + const familyClassName = this.familyClassName(family); + if(this._cachedSvgIcons.has(familyClassName)) { + const familyRegistry = this._cachedSvgIcons.get(familyClassName) as Map; return familyRegistry.has(name); } @@ -169,7 +170,8 @@ export class IgxIconService { * ``` */ public getSvgIcon(name: string, family: string = '') { - return this._cachedSvgIcons.get(family)?.get(name); + const familyClassName = this.familyClassName(family); + return this._cachedSvgIcons.get(familyClassName)?.get(name); } /** diff --git a/src/app/icon/icon.sample.html b/src/app/icon/icon.sample.html index 625b60acf75..11df8cbd4a9 100644 --- a/src/app/icon/icon.sample.html +++ b/src/app/icon/icon.sample.html @@ -86,7 +86,7 @@

Using SVG Icons

- +
diff --git a/src/app/icon/icon.sample.ts b/src/app/icon/icon.sample.ts index 341e3427249..743d15d4b05 100644 --- a/src/app/icon/icon.sample.ts +++ b/src/app/icon/icon.sample.ts @@ -19,6 +19,6 @@ export class IconSampleComponent implements OnInit { this._iconService.addSvgIcon('equals', '/assets/svg/filtering/equals.svg', 'svg-flags'); this._iconService.addSvgIcon('is_empty', '/assets/svg/filtering/is_empty.svg', 'svg-flags'); this._iconService.addSvgIcon('starts_with', '/assets/svg/filtering/starts_with.svg', 'svg-flags'); - this._iconService.addSvgIcon('copy', '/assets/svg/filtering/copy.svg', 'svg-flags'); + this._iconService.addSvgIcon('copy', '/assets/svg/filtering/copy.svg'); } } From 64690d3e3369c3691c457b979310f192f83365f4 Mon Sep 17 00:00:00 2001 From: plamenamiteva Date: Mon, 11 Oct 2021 18:57:39 +0300 Subject: [PATCH 33/36] fix(overlay): fix overlay closing animation duration --- projects/igniteui-angular/src/lib/services/overlay/overlay.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/projects/igniteui-angular/src/lib/services/overlay/overlay.ts b/projects/igniteui-angular/src/lib/services/overlay/overlay.ts index 9c3452f679a..e97f1a6081a 100644 --- a/projects/igniteui-angular/src/lib/services/overlay/overlay.ts +++ b/projects/igniteui-angular/src/lib/services/overlay/overlay.ts @@ -745,9 +745,6 @@ export class IgxOverlayService implements OnDestroy { wrapperElement.style.transitionDuration = '0ms'; return; } - if (animationOptions.type === AnimationMetadataType.AnimateRef) { - animationOptions = (animationOptions as AnimationAnimateRefMetadata).animation; - } if (!animationOptions.options || !animationOptions.options.params) { return; } @@ -893,6 +890,7 @@ export class IgxOverlayService implements OnDestroy { private removeModalClasses(info: OverlayInfo) { if (info.settings.modal) { const wrapperElement = info.elementRef.nativeElement.parentElement.parentElement; + this.applyAnimationParams(wrapperElement, info.settings.positionStrategy.settings.closeAnimation); wrapperElement.classList.remove('igx-overlay__wrapper--modal'); wrapperElement.classList.add('igx-overlay__wrapper'); } From 13f2c8cec13ce4260e19038acf9ea59890d81593 Mon Sep 17 00:00:00 2001 From: viktorkombov Date: Tue, 12 Oct 2021 09:59:23 +0300 Subject: [PATCH 34/36] fix(grid): update extractDataFromSelection method --- projects/igniteui-angular/src/lib/grids/grid-base.directive.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/projects/igniteui-angular/src/lib/grids/grid-base.directive.ts b/projects/igniteui-angular/src/lib/grids/grid-base.directive.ts index 11efbf25c29..ad1e1d6716b 100644 --- a/projects/igniteui-angular/src/lib/grids/grid-base.directive.ts +++ b/projects/igniteui-angular/src/lib/grids/grid-base.directive.ts @@ -6942,7 +6942,7 @@ export abstract class IgxGridBaseDirective extends DisplayDensityBase implements // eslint-disable-next-line prefer-const for (let [row, set] of selectionMap) { - row = this.paginator ? row + (this.paginator.perPage * this.paginator.page) : row; + row = this.paginator && source === this.filteredSortedData ? row + (this.paginator.perPage * this.paginator.page) : row; row = isRemote ? row - this.virtualizationState.startIndex : row; if (!source[row] || source[row].detailsData !== undefined) { continue; From 5687ab5f9e18611a3881c1c71eb869d50968dbb8 Mon Sep 17 00:00:00 2001 From: Plamena Miteva Date: Tue, 12 Oct 2021 13:16:10 +0300 Subject: [PATCH 35/36] feat(dialog): update dialog's show/hide animations to fadeIn/fadeOut #9516 (#9847) --- CHANGELOG.md | 18 +++++++++++++++++- .../src/lib/dialog/dialog.component.ts | 7 +++---- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ea9fff52d53..e77f05e9e23 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,23 @@ All notable changes for each version of this project will be documented in this ### New Features - `IgxCsvExporterService`, `IgxExcelExporterService` - - Exporter services are no longer required to be provided in the application since they are now injected on a root level. + - Exporter services are no longer required to be provided in the application since they are now injected on a root level. + +### General + +- `IgxDialog` + - **Breaking Change** - The default positionSettings open/close animation has been changed to `fadeIn`/`fadeOut`. The open/close animation can be set through the position settings, e.g. change the animation to the previously default open/close animation: + + ```typescript + import { slideInBottom, slideOutTop } from 'igniteui-angular'; + + @ViewChild('alert', { static: true }) public alert: IgxDialogComponent; + public newPositionSettings: PositionSettings = { + openAnimation: useAnimation(slideInBottom, { params: { fromPosition: 'translateY(100%)' } }), + closeAnimation: useAnimation(slideOutTop, { params: { toPosition: 'translateY(-100%)'} }) + }; + this.alert.positionSettings = this.newPositionSettings; + ``` ## 12.2.1 diff --git a/projects/igniteui-angular/src/lib/dialog/dialog.component.ts b/projects/igniteui-angular/src/lib/dialog/dialog.component.ts index 772df61db2f..b2d4d201291 100644 --- a/projects/igniteui-angular/src/lib/dialog/dialog.component.ts +++ b/projects/igniteui-angular/src/lib/dialog/dialog.component.ts @@ -1,4 +1,3 @@ -import { useAnimation } from '@angular/animations'; import { CommonModule } from '@angular/common'; import { Component, @@ -22,7 +21,7 @@ import { IgxRippleModule } from '../directives/ripple/ripple.directive'; import { IgxDialogActionsDirective, IgxDialogTitleDirective } from './dialog.directives'; import { IgxToggleModule, IgxToggleDirective } from '../directives/toggle/toggle.directive'; import { OverlaySettings, GlobalPositionStrategy, NoOpScrollStrategy, PositionSettings } from '../services/public_api'; -import { slideInBottom, slideOutTop } from '../animations/slide/index'; +import {fadeIn, fadeOut} from '../animations/fade/index'; import { IgxFocusModule } from '../directives/focus/focus.directive'; import { CancelableEventArgs, IBaseEventArgs } from '../core/utils'; @@ -459,8 +458,8 @@ export class IgxDialogComponent implements IToggleView, OnInit, OnDestroy, After protected destroy$ = new Subject(); private _positionSettings: PositionSettings = { - openAnimation: useAnimation(slideInBottom, { params: { fromPosition: 'translateY(100%)' } }), - closeAnimation: useAnimation(slideOutTop, { params: { toPosition: 'translateY(-100%)' } }) + openAnimation: fadeIn, + closeAnimation: fadeOut }; private _overlayDefaultSettings: OverlaySettings; From addda51fa9aeacfe50adff6c1934680ab0923c1d Mon Sep 17 00:00:00 2001 From: viktorkombov Date: Thu, 14 Oct 2021 14:34:11 +0300 Subject: [PATCH 36/36] test(grid): add unit test covering all the new code --- .../lib/grids/grid/grid.master-detail.spec.ts | 48 +++++++++++++++++-- 1 file changed, 45 insertions(+), 3 deletions(-) diff --git a/projects/igniteui-angular/src/lib/grids/grid/grid.master-detail.spec.ts b/projects/igniteui-angular/src/lib/grids/grid/grid.master-detail.spec.ts index 603df03990c..3cf6b8eea95 100644 --- a/projects/igniteui-angular/src/lib/grids/grid/grid.master-detail.spec.ts +++ b/projects/igniteui-angular/src/lib/grids/grid/grid.master-detail.spec.ts @@ -3,7 +3,7 @@ import { TestBed, ComponentFixture, fakeAsync, tick } from '@angular/core/testin import { configureTestSuite } from '../../test-utils/configure-suite'; import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { By } from '@angular/platform-browser'; -import { UIInteractions, wait, waitForActiveNodeChange} from '../../test-utils/ui-interactions.spec'; +import { UIInteractions, wait, waitForActiveNodeChange } from '../../test-utils/ui-interactions.spec'; import { IgxGridModule } from './public_api'; import { IgxGridComponent } from './grid.component'; import { IgxGridRowComponent } from './grid-row.component'; @@ -42,7 +42,7 @@ describe('IgxGrid Master Detail #grid', () => { })); describe('Basic', () => { - beforeEach( fakeAsync(() => { + beforeEach(fakeAsync(() => { fix = TestBed.createComponent(DefaultGridMasterDetailComponent); fix.detectChanges(); grid = fix.componentInstance.grid; @@ -689,7 +689,7 @@ describe('IgxGrid Master Detail #grid', () => { describe('Integration', () => { describe('Paging', () => { - it('Should not take into account expanded detail views as additional records.', fakeAsync(() => { + it('Should not take into account expanded detail views as additional records.', fakeAsync(() => { fix = TestBed.createComponent(DefaultGridMasterDetailComponent); grid = fix.componentInstance.grid; fix.detectChanges(); @@ -859,6 +859,48 @@ describe('IgxGrid Master Detail #grid', () => { fix.detectChanges(); expect(grid.getSelectedData()).toEqual(expectedData); })); + + it('getSelectedData should return correct values when there are master details and paging is enabled', fakeAsync(() => { + const range = { rowStart: 0, rowEnd: 5, columnStart: 'ContactName', columnEnd: 'ContactName' }; + const expectedDataFromSecondPage = [ + { ContactName: 'Hanna Moos' }, + { ContactName: 'Frédérique Citeaux' }, + { ContactName: 'Martín Sommer' } + ]; + fix.componentInstance.paging = true; + fix.detectChanges(); + grid.paginator.perPage = 5; + fix.detectChanges(); + tick(16); + grid.paginator.paginate(1); + fix.detectChanges(); + tick(16); + + grid.expandAll(); + tick(100); + fix.detectChanges(); + + grid.selectRange(range); + fix.detectChanges(); + expect(grid.getSelectedData()).toEqual(expectedDataFromSecondPage); + + const expectedDataFromThirdPage = [ + { ContactName: 'Victoria Ashworth' }, + { ContactName: 'Patricio Simpson' }, + { ContactName: 'Francisco Chang' } + ]; + grid.paginator.paginate(2); + fix.detectChanges(); + tick(16); + + grid.expandAll(); + tick(100); + fix.detectChanges(); + + grid.selectRange(range); + fix.detectChanges(); + expect(grid.getSelectedData()).toEqual(expectedDataFromThirdPage); + })); }); describe('Row Selection', () => {