From 08962fef172e79ebafc65bd509e2e8114abc5ba7 Mon Sep 17 00:00:00 2001 From: SAndreeva Date: Mon, 3 Dec 2018 16:25:29 +0200 Subject: [PATCH 01/28] fix(grid): mark grid for check inside NgZone when resizing #2792 --- .../src/lib/grids/grid-column-resizing.service.ts | 10 +++++++--- .../src/lib/grids/grid-header.component.ts | 6 +----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/projects/igniteui-angular/src/lib/grids/grid-column-resizing.service.ts b/projects/igniteui-angular/src/lib/grids/grid-column-resizing.service.ts index a5eac5e8ed2..fd6cfe3ff5f 100644 --- a/projects/igniteui-angular/src/lib/grids/grid-column-resizing.service.ts +++ b/projects/igniteui-angular/src/lib/grids/grid-column-resizing.service.ts @@ -1,4 +1,4 @@ -import { Injectable } from '@angular/core'; +import { Injectable, NgZone } from '@angular/core'; import { isFirefox } from '../core/utils'; import { IgxColumnComponent } from './column.component'; @@ -37,6 +37,8 @@ export class IgxColumnResizingService { */ public column: IgxColumnComponent; + constructor(private zone: NgZone) { } + /** * Returns the minimal possible width to which the column can be resized. @@ -104,7 +106,9 @@ export class IgxColumnResizingService { this.column.width = size; } - this.column.grid.markForCheck(); + + this.zone.run(() => this.column.grid.markForCheck()); + this.column.grid.reflow(); this.column.grid.onColumnResized.emit({ column: this.column, @@ -145,7 +149,7 @@ export class IgxColumnResizingService { this.column.width = (currentColWidth + diff) + 'px'; } - this.column.grid.markForCheck(); + this.zone.run(() => this.column.grid.markForCheck()); this.column.grid.reflow(); if (currentColWidth !== parseFloat(this.column.width)) { diff --git a/projects/igniteui-angular/src/lib/grids/grid-header.component.ts b/projects/igniteui-angular/src/lib/grids/grid-header.component.ts index 718532aecf8..77595793a50 100644 --- a/projects/igniteui-angular/src/lib/grids/grid-header.component.ts +++ b/projects/igniteui-angular/src/lib/grids/grid-header.component.ts @@ -27,7 +27,7 @@ import { IgxColumnResizingService } from './grid-column-resizing.service'; selector: 'igx-grid-header', templateUrl: './grid-header.component.html' }) -export class IgxGridHeaderComponent implements OnInit, DoCheck { +export class IgxGridHeaderComponent implements DoCheck { @Input() public column: IgxColumnComponent; @@ -113,10 +113,6 @@ export class IgxGridHeaderComponent implements OnInit, DoCheck { public filteringService: IgxFilteringService ) { } - public ngOnInit() { - this.column.columnGroup ? this.zone.runTask(() => this.cdr.markForCheck()) : - this.cdr.markForCheck(); - } public ngDoCheck() { this.getSortDirection(); From 9dbf3e47c85ef1c2cce6837f5a12bb40d87e5e3f Mon Sep 17 00:00:00 2001 From: MartinKamenov Date: Tue, 4 Dec 2018 12:18:18 +0200 Subject: [PATCH 02/28] chore(*): Emmiting onSortingDone in chip. --- .../igniteui-angular/src/lib/grids/grid/grid.component.ts | 6 ++++++ 1 file changed, 6 insertions(+) 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 8ccb1f33af6..c445155ae97 100644 --- a/projects/igniteui-angular/src/lib/grids/grid/grid.component.ts +++ b/projects/igniteui-angular/src/lib/grids/grid/grid.component.ts @@ -743,6 +743,12 @@ export class IgxGridComponent extends IgxGridBaseComponent implements OnInit, Do const columnExpr = sortingExpr.find((expr) => expr.fieldName === event.owner.id); columnExpr.dir = 3 - columnExpr.dir; this.sort(columnExpr); + this.onSortingDone.emit({ + dir: columnExpr.dir, + fieldName: columnExpr.fieldName, + ignoreCase: columnExpr.ignoreCase, + strategy: columnExpr.strategy + }); this.markForCheck(); } From c9e73df841840491a95d5a42118ed2696b92e865 Mon Sep 17 00:00:00 2001 From: MartinKamenov Date: Wed, 5 Dec 2018 11:01:07 +0200 Subject: [PATCH 03/28] chore(*): Emiiting onSortingDone in sorting method. --- .../igniteui-angular/src/lib/grids/grid-base.component.ts | 6 ++++++ .../igniteui-angular/src/lib/grids/grid-header.component.ts | 6 ------ .../igniteui-angular/src/lib/grids/grid/grid.component.ts | 6 ------ 3 files changed, 6 insertions(+), 12 deletions(-) diff --git a/projects/igniteui-angular/src/lib/grids/grid-base.component.ts b/projects/igniteui-angular/src/lib/grids/grid-base.component.ts index a37eb5ede07..fa88219ae1c 100644 --- a/projects/igniteui-angular/src/lib/grids/grid-base.component.ts +++ b/projects/igniteui-angular/src/lib/grids/grid-base.component.ts @@ -3646,6 +3646,12 @@ export abstract class IgxGridBaseComponent extends DisplayDensityBase implements */ protected _sort(expression: ISortingExpression) { this.gridAPI.sort(this.id, expression); + this.onSortingDone.emit({ + dir: expression.dir, + fieldName: expression.fieldName, + ignoreCase: expression.ignoreCase, + strategy: expression.strategy + }); } /** diff --git a/projects/igniteui-angular/src/lib/grids/grid-header.component.ts b/projects/igniteui-angular/src/lib/grids/grid-header.component.ts index 718532aecf8..893e65975e3 100644 --- a/projects/igniteui-angular/src/lib/grids/grid-header.component.ts +++ b/projects/igniteui-angular/src/lib/grids/grid-header.component.ts @@ -141,12 +141,6 @@ export class IgxGridHeaderComponent implements OnInit, DoCheck { this.sortDirection = sortDir; this.grid.sort({ fieldName: this.column.field, dir: this.sortDirection, ignoreCase: this.column.sortingIgnoreCase, strategy: this.column.sortStrategy }); - this.grid.onSortingDone.emit({ - dir: this.sortDirection, - fieldName: this.column.field, - ignoreCase: this.column.sortingIgnoreCase, - strategy: this.column.sortStrategy - }); } } } 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 c445155ae97..8ccb1f33af6 100644 --- a/projects/igniteui-angular/src/lib/grids/grid/grid.component.ts +++ b/projects/igniteui-angular/src/lib/grids/grid/grid.component.ts @@ -743,12 +743,6 @@ export class IgxGridComponent extends IgxGridBaseComponent implements OnInit, Do const columnExpr = sortingExpr.find((expr) => expr.fieldName === event.owner.id); columnExpr.dir = 3 - columnExpr.dir; this.sort(columnExpr); - this.onSortingDone.emit({ - dir: columnExpr.dir, - fieldName: columnExpr.fieldName, - ignoreCase: columnExpr.ignoreCase, - strategy: columnExpr.strategy - }); this.markForCheck(); } From 76affc8fc635770e991506c67d5ffad61b30c2e0 Mon Sep 17 00:00:00 2001 From: SAndreeva Date: Wed, 5 Dec 2018 18:58:44 +0200 Subject: [PATCH 04/28] fix(grid): address review comments #2792 --- .../src/lib/grids/grid-column-resizing.service.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/projects/igniteui-angular/src/lib/grids/grid-column-resizing.service.ts b/projects/igniteui-angular/src/lib/grids/grid-column-resizing.service.ts index fd6cfe3ff5f..ea4020797db 100644 --- a/projects/igniteui-angular/src/lib/grids/grid-column-resizing.service.ts +++ b/projects/igniteui-angular/src/lib/grids/grid-column-resizing.service.ts @@ -106,8 +106,7 @@ export class IgxColumnResizingService { this.column.width = size; } - - this.zone.run(() => this.column.grid.markForCheck()); + this.zone.run(() => {}); this.column.grid.reflow(); this.column.grid.onColumnResized.emit({ @@ -149,7 +148,7 @@ export class IgxColumnResizingService { this.column.width = (currentColWidth + diff) + 'px'; } - this.zone.run(() => this.column.grid.markForCheck()); + this.zone.run(() => {}); this.column.grid.reflow(); if (currentColWidth !== parseFloat(this.column.width)) { From d445386f96fee712f29137fdca42c6f482185896 Mon Sep 17 00:00:00 2001 From: MartinKamenov Date: Thu, 6 Dec 2018 17:53:36 +0200 Subject: [PATCH 05/28] chore(*): Emitting onSortingDone when sorting multiple columns. --- .../src/lib/grids/grid-base.component.ts | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/projects/igniteui-angular/src/lib/grids/grid-base.component.ts b/projects/igniteui-angular/src/lib/grids/grid-base.component.ts index fa88219ae1c..203d50d5f35 100644 --- a/projects/igniteui-angular/src/lib/grids/grid-base.component.ts +++ b/projects/igniteui-angular/src/lib/grids/grid-base.component.ts @@ -998,7 +998,7 @@ export abstract class IgxGridBaseComponent extends DisplayDensityBase implements * @memberof IgxGridBaseComponent */ @Output() - public onSortingDone = new EventEmitter(); + public onSortingDone = new EventEmitter>(); /** * Emitted when filtering is performed through the UI. @@ -3018,9 +3018,13 @@ export abstract class IgxGridBaseComponent extends DisplayDensityBase implements public sort(...rest): void { this.endEdit(false); if (rest.length === 1 && rest[0] instanceof Array) { - this._sortMultiple(rest[0]); + const expressions: Array = rest[0]; + this._sortMultiple(expressions); + this.onSortingDone.emit(expressions); } else { - this._sort(rest[0]); + const expression: ISortingExpression = rest[0]; + this._sort(expression); + this.onSortingDone.emit(expression); } } @@ -3646,12 +3650,6 @@ export abstract class IgxGridBaseComponent extends DisplayDensityBase implements */ protected _sort(expression: ISortingExpression) { this.gridAPI.sort(this.id, expression); - this.onSortingDone.emit({ - dir: expression.dir, - fieldName: expression.fieldName, - ignoreCase: expression.ignoreCase, - strategy: expression.strategy - }); } /** From c8ec40ac0c903cba699a183a91adfd2d4bc232f2 Mon Sep 17 00:00:00 2001 From: MartinKamenov Date: Mon, 10 Dec 2018 09:28:23 +0200 Subject: [PATCH 06/28] chore(*): Remove repeating code. --- projects/igniteui-angular/src/lib/grids/grid-base.component.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/projects/igniteui-angular/src/lib/grids/grid-base.component.ts b/projects/igniteui-angular/src/lib/grids/grid-base.component.ts index 8410551b914..887ab5b11ef 100644 --- a/projects/igniteui-angular/src/lib/grids/grid-base.component.ts +++ b/projects/igniteui-angular/src/lib/grids/grid-base.component.ts @@ -3154,11 +3154,10 @@ export abstract class IgxGridBaseComponent extends DisplayDensityBase implements this.endEdit(false); if (expression instanceof Array) { this.gridAPI.sort_multiple(this.id, expression); - this.onSortingDone.emit(expression); } else { this.gridAPI.sort(this.id, expression); - this.onSortingDone.emit(expression); } + this.onSortingDone.emit(expression); } /** From 154537460e3b155359d80b947d67b0d302ecaf7b Mon Sep 17 00:00:00 2001 From: MPopov Date: Mon, 10 Dec 2018 15:47:18 +0200 Subject: [PATCH 07/28] Fix IE11 bug with toolbar height --- .../styles/components/grid-toolbar/_grid-toolbar-theme.scss | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/projects/igniteui-angular/src/lib/core/styles/components/grid-toolbar/_grid-toolbar-theme.scss b/projects/igniteui-angular/src/lib/core/styles/components/grid-toolbar/_grid-toolbar-theme.scss index 604eb0fce95..36cda1bf5e4 100644 --- a/projects/igniteui-angular/src/lib/core/styles/components/grid-toolbar/_grid-toolbar-theme.scss +++ b/projects/igniteui-angular/src/lib/core/styles/components/grid-toolbar/_grid-toolbar-theme.scss @@ -156,7 +156,7 @@ padding: map-get($grid-toolbar-padding, 'cosy'); border-bottom: 1px solid igx-color(map-get($theme, 'palette'), 'grays', 300); background: --var($theme, 'background-color'); - min-height: map-get($grid-toolbar-height, 'comfortable'); + height: map-get($grid-toolbar-height, 'comfortable'); %igx-button--flat { background: --var($theme, 'button-background'); @@ -232,12 +232,12 @@ } %igx-grid-toolbar--cosy { - min-height: map-get($grid-toolbar-height, 'cosy'); + height: map-get($grid-toolbar-height, 'cosy'); padding: map-get($grid-toolbar-padding, 'cosy'); } %igx-grid-toolbar--compact { - min-height: map-get($grid-toolbar-height, 'compact'); + height: map-get($grid-toolbar-height, 'compact'); padding: map-get($grid-toolbar-padding, 'compact'); } From 1dcf1b3f51540e15b9c032e2152e272cd073532e Mon Sep 17 00:00:00 2001 From: Simeon Simeonoff Date: Mon, 10 Dec 2018 18:52:56 +0200 Subject: [PATCH 08/28] fix(themes): igx-contrast-color returns wrong color for rgba Closes #3384 --- .../src/lib/core/styles/base/utilities/_functions.scss | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/projects/igniteui-angular/src/lib/core/styles/base/utilities/_functions.scss b/projects/igniteui-angular/src/lib/core/styles/base/utilities/_functions.scss index 78576d153e6..a2dd29cc2ff 100644 --- a/projects/igniteui-angular/src/lib/core/styles/base/utilities/_functions.scss +++ b/projects/igniteui-angular/src/lib/core/styles/base/utilities/_functions.scss @@ -113,11 +113,14 @@ /// @param {Map} $palette - The source palette map. /// @param {string} $color - The target color from the color palette. /// @param {number|variant} $variant - The target color shade from the color palette. +/// @requires igx-color +/// @requires text-contrast +/// @requires hexrgba /// @returns {Color} [#fff] - Returns white if now palette, color and/or variant matches found. @function igx-contrast-color($palette, $color, $variant: 500) { $_color: igx-color($palette, $color, $variant); @if $_color { - @return text-contrast($_color); + @return text-contrast(hexrgba($_color)); } @return #fff; } From 8e9eacd74eedeff2666313d26d3b02534210f718 Mon Sep 17 00:00:00 2001 From: wnvko Date: Tue, 11 Dec 2018 15:22:04 +0200 Subject: [PATCH 09/28] fix(igxTransaction): call onStateUpdate in endPending, #2921 --- .../src/lib/services/transaction/igx-transaction.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/projects/igniteui-angular/src/lib/services/transaction/igx-transaction.ts b/projects/igniteui-angular/src/lib/services/transaction/igx-transaction.ts index 82851be8b4e..1c9d3b939d7 100644 --- a/projects/igniteui-angular/src/lib/services/transaction/igx-transaction.ts +++ b/projects/igniteui-angular/src/lib/services/transaction/igx-transaction.ts @@ -116,6 +116,7 @@ export class IgxTransactionService exten this._isPending = false; if (commit) { const actions: { transaction: T, recordRef: any }[] = []; + // don't use addTransaction due to custom undo handling for (const transaction of this._pendingTransactions) { const pendingState = this._pendingStates.get(transaction.id); this._transactions.push(transaction); @@ -125,6 +126,8 @@ export class IgxTransactionService exten this._undoStack.push(actions); this._redoStack = []; + + this.onStateUpdate.emit(); } super.endPending(commit); } From 6de7ce25507cf0b5d4ffebbc93206112d5892a98 Mon Sep 17 00:00:00 2001 From: wnvko Date: Tue, 11 Dec 2018 15:37:47 +0200 Subject: [PATCH 10/28] test(igxTransaction): add tests for onStateUpdate event, #2921 --- .../transaction/igx-transaction.spec.ts | 45 +++++++++++++++++-- 1 file changed, 41 insertions(+), 4 deletions(-) diff --git a/projects/igniteui-angular/src/lib/services/transaction/igx-transaction.spec.ts b/projects/igniteui-angular/src/lib/services/transaction/igx-transaction.spec.ts index e207da45939..f7cf8205be7 100644 --- a/projects/igniteui-angular/src/lib/services/transaction/igx-transaction.spec.ts +++ b/projects/igniteui-angular/src/lib/services/transaction/igx-transaction.spec.ts @@ -3,7 +3,7 @@ import { Transaction, TransactionType, HierarchicalTransaction } from './transac import { SampleTestData } from '../../test-utils/sample-test-data.spec'; import { IgxHierarchicalTransactionService } from './igx-hierarchical-transaction'; -describe('IgxTransaction', () => { +fdescribe('IgxTransaction', () => { describe('IgxTransaction UNIT tests', () => { it('Should initialize transactions log properly', () => { const trans = new IgxTransactionService(); @@ -161,8 +161,9 @@ describe('IgxTransaction', () => { expect(trans.getTransactionLog('100').pop()).toEqual(undefined); }); - it('Should add ADD type transaction - all feasible paths', () => { + it('Should add ADD type transaction - all feasible paths, and correctly fires onStateUpdate', () => { const trans = new IgxTransactionService(); + spyOn(trans.onStateUpdate, 'emit').and.callThrough(); expect(trans).toBeDefined(); // ADD @@ -176,18 +177,24 @@ describe('IgxTransaction', () => { recordRef: undefined, type: addTransaction.type }); + expect(trans.onStateUpdate.emit).toHaveBeenCalledTimes(1); + trans.clear(); expect(trans.getState('1')).toBeUndefined(); expect(trans.getAggregatedValue('1', true)).toBeNull(); expect(trans.getTransactionLog()).toEqual([]); expect(trans.getAggregatedChanges(true)).toEqual([]); + expect(trans.onStateUpdate.emit).toHaveBeenCalledTimes(2); // ADD -> Undo trans.add(addTransaction); trans.undo(); expect(trans.getTransactionLog()).toEqual([]); expect(trans.getAggregatedChanges(true)).toEqual([]); + expect(trans.onStateUpdate.emit).toHaveBeenCalledTimes(4); + trans.clear(); + expect(trans.onStateUpdate.emit).toHaveBeenCalledTimes(5); // ADD -> Undo -> Redo trans.add(addTransaction); @@ -199,7 +206,10 @@ describe('IgxTransaction', () => { recordRef: undefined, type: addTransaction.type }); + expect(trans.onStateUpdate.emit).toHaveBeenCalledTimes(8); + trans.clear(); + expect(trans.onStateUpdate.emit).toHaveBeenCalledTimes(9); // ADD -> DELETE trans.add(addTransaction); @@ -207,7 +217,10 @@ describe('IgxTransaction', () => { trans.add(deleteTransaction); expect(trans.getTransactionLog()).toEqual([addTransaction, deleteTransaction]); expect(trans.getAggregatedChanges(true)).toEqual([]); + expect(trans.onStateUpdate.emit).toHaveBeenCalledTimes(11); + trans.clear(); + expect(trans.onStateUpdate.emit).toHaveBeenCalledTimes(12); // ADD -> DELETE -> Undo trans.add(addTransaction); @@ -219,7 +232,10 @@ describe('IgxTransaction', () => { recordRef: undefined, type: addTransaction.type }); + expect(trans.onStateUpdate.emit).toHaveBeenCalledTimes(15); + trans.clear(); + expect(trans.onStateUpdate.emit).toHaveBeenCalledTimes(16); // ADD -> DELETE -> Undo -> Redo trans.add(addTransaction); @@ -228,7 +244,10 @@ describe('IgxTransaction', () => { trans.redo(); expect(trans.getTransactionLog()).toEqual([addTransaction, deleteTransaction]); expect(trans.getAggregatedChanges(true)).toEqual([]); + expect(trans.onStateUpdate.emit).toHaveBeenCalledTimes(20); + trans.clear(); + expect(trans.onStateUpdate.emit).toHaveBeenCalledTimes(21); // ADD -> DELETE -> Undo -> Undo trans.add(addTransaction); @@ -237,7 +256,10 @@ describe('IgxTransaction', () => { trans.undo(); expect(trans.getTransactionLog()).toEqual([]); expect(trans.getAggregatedChanges(true)).toEqual([]); + expect(trans.onStateUpdate.emit).toHaveBeenCalledTimes(25); + trans.clear(); + expect(trans.onStateUpdate.emit).toHaveBeenCalledTimes(26); // ADD -> UPDATE trans.add(addTransaction); @@ -249,7 +271,10 @@ describe('IgxTransaction', () => { recordRef: undefined, type: addTransaction.type }); + expect(trans.onStateUpdate.emit).toHaveBeenCalledTimes(28); + trans.clear(); + expect(trans.onStateUpdate.emit).toHaveBeenCalledTimes(29); // ADD -> UPDATE -> Undo trans.add(addTransaction); @@ -261,7 +286,10 @@ describe('IgxTransaction', () => { recordRef: undefined, type: addTransaction.type }); + expect(trans.onStateUpdate.emit).toHaveBeenCalledTimes(32); + trans.clear(); + expect(trans.onStateUpdate.emit).toHaveBeenCalledTimes(33); // ADD -> UPDATE -> Undo -> Redo trans.add(addTransaction); @@ -274,7 +302,10 @@ describe('IgxTransaction', () => { recordRef: undefined, type: addTransaction.type }); + expect(trans.onStateUpdate.emit).toHaveBeenCalledTimes(37); + trans.clear(); + expect(trans.onStateUpdate.emit).toHaveBeenCalledTimes(38); }); it('Should add DELETE type transaction - all feasible paths', () => { @@ -540,8 +571,10 @@ describe('IgxTransaction', () => { expect(originalData[49]).toEqual('Added Row'); }); - it('Should add pending transaction and push it to transaction log', () => { + it('Should add pending transaction and push it to transaction log, and correctly fires onStateUpdate', () => { const trans = new IgxTransactionService(); + spyOn(trans.onStateUpdate, 'emit').and.callThrough(); + expect(trans).toBeDefined(); const recordRef = { key: 'Key1', value1: 1, value2: 2, value3: 3 }; let newValue: any = { key: 'Key1', value1: 10 }; @@ -585,10 +618,13 @@ describe('IgxTransaction', () => { recordRef: recordRef, type: updateTransaction.type }); + expect(trans.onStateUpdate.emit).toHaveBeenCalledTimes(1); }); - it('Should not add pending transaction and push it to transaction log', () => { + it('Should not add pending transaction and push it to transaction log, and correctly fires onStateUpdate', () => { const trans = new IgxTransactionService(); + spyOn(trans.onStateUpdate, 'emit').and.callThrough(); + expect(trans).toBeDefined(); const recordRef = { key: 'Key1', value1: 1, value2: 2, value3: 3 }; let newValue: any = { key: 'Key1', value1: 10 }; @@ -611,6 +647,7 @@ describe('IgxTransaction', () => { expect(trans.getTransactionLog()).toEqual([]); expect(trans.getAggregatedChanges(true)).toEqual([]); + expect(trans.onStateUpdate.emit).toHaveBeenCalledTimes(0); }); }); From d9f1fe4b200090a2f055374d1999f203a018d70b Mon Sep 17 00:00:00 2001 From: Radko Kolev Date: Tue, 11 Dec 2018 15:49:01 +0200 Subject: [PATCH 11/28] feat(grid-toolbar): making toolbar to render title SPAN only when needed #3397 --- .../components/grid-toolbar/_grid-toolbar-theme.scss | 2 +- .../src/lib/grids/grid-toolbar.component.html | 2 +- src/app/grid-toolbar/grid-toolbar-custom.sample.html | 12 +++++++++--- src/app/grid-toolbar/grid-toolbar-custom.sample.ts | 7 +++++-- 4 files changed, 16 insertions(+), 7 deletions(-) diff --git a/projects/igniteui-angular/src/lib/core/styles/components/grid-toolbar/_grid-toolbar-theme.scss b/projects/igniteui-angular/src/lib/core/styles/components/grid-toolbar/_grid-toolbar-theme.scss index 604eb0fce95..949c557e31c 100644 --- a/projects/igniteui-angular/src/lib/core/styles/components/grid-toolbar/_grid-toolbar-theme.scss +++ b/projects/igniteui-angular/src/lib/core/styles/components/grid-toolbar/_grid-toolbar-theme.scss @@ -150,7 +150,7 @@ %igx-grid-toolbar { display: flex; align-items: center; - justify-content: space-between; + justify-content: flex-end; grid-row: 1; font-size: $grid-toolbar-fs; padding: map-get($grid-toolbar-padding, 'cosy'); diff --git a/projects/igniteui-angular/src/lib/grids/grid-toolbar.component.html b/projects/igniteui-angular/src/lib/grids/grid-toolbar.component.html index 20935efa6ba..7645f2992ed 100644 --- a/projects/igniteui-angular/src/lib/grids/grid-toolbar.component.html +++ b/projects/igniteui-angular/src/lib/grids/grid-toolbar.component.html @@ -1,4 +1,4 @@ - + {{ getTitle() }} diff --git a/src/app/grid-toolbar/grid-toolbar-custom.sample.html b/src/app/grid-toolbar/grid-toolbar-custom.sample.html index e9c3af3360b..17a3c254fbd 100644 --- a/src/app/grid-toolbar/grid-toolbar-custom.sample.html +++ b/src/app/grid-toolbar/grid-toolbar-custom.sample.html @@ -7,20 +7,18 @@

Toolbar

- @@ -36,6 +34,14 @@

Toolbar

+ +
Toolbar +
Column Hiding +
Column Pinning +
Export Excel +
Export CSV +
+
diff --git a/src/app/grid-toolbar/grid-toolbar-custom.sample.ts b/src/app/grid-toolbar/grid-toolbar-custom.sample.ts index a36bcc2dbc5..acef5950ef0 100644 --- a/src/app/grid-toolbar/grid-toolbar-custom.sample.ts +++ b/src/app/grid-toolbar/grid-toolbar-custom.sample.ts @@ -1,6 +1,6 @@ -import { Component } from '@angular/core'; -import { IgxColumnComponent } from 'igniteui-angular'; +import { Component, ViewChild } from '@angular/core'; +import { IgxColumnComponent, IgxGridComponent } from 'igniteui-angular'; @Component({ selector: 'app-grid-toolbar-custom-sample', @@ -9,6 +9,9 @@ import { IgxColumnComponent } from 'igniteui-angular'; }) export class GridToolbarCustomSampleComponent { + @ViewChild('grid1', { read: IgxGridComponent }) + public igxGrid1: IgxGridComponent; + data = [ { Name: 'Alice', From 5ed94d2dfc61038800ff4771c247d70fcc296764 Mon Sep 17 00:00:00 2001 From: wnvko Date: Tue, 11 Dec 2018 16:15:38 +0200 Subject: [PATCH 12/28] test(igxTransaction): error on calling getAggregatedChanges(false), #2921 --- .../lib/services/transaction/igx-transaction.spec.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/projects/igniteui-angular/src/lib/services/transaction/igx-transaction.spec.ts b/projects/igniteui-angular/src/lib/services/transaction/igx-transaction.spec.ts index f7cf8205be7..1d3cbcea927 100644 --- a/projects/igniteui-angular/src/lib/services/transaction/igx-transaction.spec.ts +++ b/projects/igniteui-angular/src/lib/services/transaction/igx-transaction.spec.ts @@ -719,6 +719,16 @@ fdescribe('IgxTransaction', () => { expect(transaction.getState(2)).toBeDefined(); expect(transaction.getState(2).type).toBe(TransactionType.DELETE); }); + + it('Should correctly call getAggregatedChanges with commit', () => { + const transaction = new IgxHierarchicalTransactionService(); + expect(transaction).toBeDefined(); + + const deleteTransaction: HierarchicalTransaction = { id: 0, type: TransactionType.DELETE, newValue: null, path: [] }; + transaction.add(deleteTransaction, 'Deleted row'); + + expect(transaction.getAggregatedChanges(false)).toBe(null); + }); }); }); From dc9241d6dd443f381ee88a98bc5d36a3527b64c3 Mon Sep 17 00:00:00 2001 From: wnvko Date: Tue, 11 Dec 2018 16:21:22 +0200 Subject: [PATCH 13/28] fix(igxTransaction): should correctly call getAggregatedChanges(false), #2921 --- .../services/transaction/igx-hierarchical-transaction.ts | 8 +++++--- .../src/lib/services/transaction/igx-transaction.spec.ts | 6 +++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/projects/igniteui-angular/src/lib/services/transaction/igx-hierarchical-transaction.ts b/projects/igniteui-angular/src/lib/services/transaction/igx-hierarchical-transaction.ts index 2f722f5d4e3..786dd331a4d 100644 --- a/projects/igniteui-angular/src/lib/services/transaction/igx-hierarchical-transaction.ts +++ b/projects/igniteui-angular/src/lib/services/transaction/igx-hierarchical-transaction.ts @@ -61,9 +61,11 @@ export class IgxHierarchicalTransactionService { }); }); - describe('IgxHierarchicalTransaction UNIT Test', () => { + fdescribe('IgxHierarchicalTransaction UNIT Test', () => { it('Should set path for each state when transaction is added in Hierarchical data source', () => { const transaction = new IgxHierarchicalTransactionService(); expect(transaction).toBeDefined(); @@ -720,14 +720,14 @@ fdescribe('IgxTransaction', () => { expect(transaction.getState(2).type).toBe(TransactionType.DELETE); }); - it('Should correctly call getAggregatedChanges with commit', () => { + it('Should correctly call getAggregatedChanges without commit when recordRef is null', () => { const transaction = new IgxHierarchicalTransactionService(); expect(transaction).toBeDefined(); const deleteTransaction: HierarchicalTransaction = { id: 0, type: TransactionType.DELETE, newValue: null, path: [] }; transaction.add(deleteTransaction, 'Deleted row'); - expect(transaction.getAggregatedChanges(false)).toBe(null); + expect(transaction.getAggregatedChanges(false)).toEqual([deleteTransaction]); }); }); }); From 090840db30b55f2d4bc569cecee6fafd24a052a6 Mon Sep 17 00:00:00 2001 From: wnvko Date: Tue, 11 Dec 2018 16:31:59 +0200 Subject: [PATCH 14/28] chore(igxTransaction): remove fdescribe from tests, #2921 --- .../src/lib/services/transaction/igx-transaction.spec.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/projects/igniteui-angular/src/lib/services/transaction/igx-transaction.spec.ts b/projects/igniteui-angular/src/lib/services/transaction/igx-transaction.spec.ts index 22c325bb148..cf839ec2070 100644 --- a/projects/igniteui-angular/src/lib/services/transaction/igx-transaction.spec.ts +++ b/projects/igniteui-angular/src/lib/services/transaction/igx-transaction.spec.ts @@ -3,7 +3,7 @@ import { Transaction, TransactionType, HierarchicalTransaction } from './transac import { SampleTestData } from '../../test-utils/sample-test-data.spec'; import { IgxHierarchicalTransactionService } from './igx-hierarchical-transaction'; -fdescribe('IgxTransaction', () => { +describe('IgxTransaction', () => { describe('IgxTransaction UNIT tests', () => { it('Should initialize transactions log properly', () => { const trans = new IgxTransactionService(); @@ -651,7 +651,7 @@ fdescribe('IgxTransaction', () => { }); }); - fdescribe('IgxHierarchicalTransaction UNIT Test', () => { + describe('IgxHierarchicalTransaction UNIT Test', () => { it('Should set path for each state when transaction is added in Hierarchical data source', () => { const transaction = new IgxHierarchicalTransactionService(); expect(transaction).toBeDefined(); From 3040b8abb32c3ff020012a77173a3eb19decf1e8 Mon Sep 17 00:00:00 2001 From: HristoP96 Date: Wed, 12 Dec 2018 12:12:06 +0200 Subject: [PATCH 15/28] docs(readme): Update Crypto App and Directive and Component table. --- README.md | 46 +++++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index 217640b95f5..3855af2148d 100644 --- a/README.md +++ b/README.md @@ -24,28 +24,28 @@ Current list of controls include: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | | **avatar** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/avatar/README.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/avatar.html) | | **button** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/directives/button/README.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/button.html) | | **badge** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/badge/README.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/badge.html) | | **dragdrop** | InProgress | [Readme](https://github.com/IgniteUI/igniteui-angular/tree/master/projects/igniteui-angular/src/lib/directives/dragdrop/README.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/drag_drop.html) | -| **banner** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/banner/README.md) | | | **filter** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/directives/filter/README-FILTER.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/list.html) | -| **buttonGroup** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/buttonGroup/README.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/buttongroup.html) | | **focus** | Available | | | -| **calendar** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/calendar/README.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/calendar.html) | | **forOf** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/directives/for-of/README.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/for_of.html) | -| **card** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/card/README.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/card.html) | | **hint** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/tree/master/projects/igniteui-angular/src/lib/input-group/README.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/input_group.html) | -| **carousel** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/carousel/README.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/carousel.html) | | **input** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/directives/input/README.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/input_group.html) | -| **checkbox** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/checkbox/README.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/checkbox.html) | | **label** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/directives/label/README.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/input_group.html) | -| **chips** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/chips/README.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/chip.html) | | **layout** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/directives/layout/README.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/layout.html) | -| **circular progress** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/progressbar/README.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/circular_progress.html) | | **mask** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/directives/mask/README.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/mask.html) | -| **combo** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/combo/README.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/combo.html) | | **prefix** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/input-group/README.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/input_group.html) | -| **datePicker** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/date-picker/README.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/date_picker.html) | | **radio-group** | Available | | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/radio_button.html#radio-group)| -| **dialog** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/dialog/README.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/dialog.html) | | **ripple** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/directives/ripple/README.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/button.html) | -| **drop down** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/drop-down/README.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/drop_down.html) | | **scroll-inertia** | Available | | | -| **expansion-panel** | Available | | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/expansion_panel.html) | | **suffix** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/tree/master/projects/igniteui-angular/src/lib/input-group/README.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/input_group.html) | -| **grid** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/grids/README.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/grid.html) | | **template-outlet** | Available | | | -| **icon** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/icon/README.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/icon.html) | | **text-highlight** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/tree/master/projects/igniteui-angular/src/lib/directives/text-highlight/README.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/texthighlight.html) | -| **input group** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/input-group/README.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/input_group.html) | | **text-selection** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/tree/master/projects/igniteui-angular/src/lib/directives/text-selection/README.md) | | | -| **linear progress** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/tree/master/projects/igniteui-angular/src/lib/progressbar) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/linear_progress.html) | | **toggle** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/directives/toggle/README.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/toggle.html) | -| **list** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/list/README.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/list.html) | | **tooltip** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/directives/tooltip/README.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/tooltip.html) | -| **navbar** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/navbar/README.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/navbar.html) | | *Others* | Status | Docs | | -| **navigation drawer** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/navigation-drawer/README.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/navdrawer.html) | | **Animations** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/animations/README.md) | | -| **radio** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/radio/README.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/radio_button.html) | | **dataUtil** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/data-operations/README-DATAUTIL.md) | | -| **slider** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/slider/README.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/slider.html) | | **dataContainer** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/data-operations/README-DATACONTAINER.md) | | +| **banner** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/banner/README.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/banner.html) | | **filter** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/directives/filter/README-FILTER.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/list.html) | +| **buttonGroup** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/buttonGroup/README.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/buttongroup.html) | | **forOf** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/directives/for-of/README.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/for_of.html) | +| **calendar** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/calendar/README.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/calendar.html) | | **hint** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/tree/master/projects/igniteui-angular/src/lib/input-group/README.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/input_group.html) | +| **card** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/card/README.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/card.html) | | **input** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/directives/input/README.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/input_group.html) | +| **carousel** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/carousel/README.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/carousel.html) | | **label** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/directives/label/README.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/input_group.html) | +| **checkbox** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/checkbox/README.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/checkbox.html) | | **layout** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/directives/layout/README.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/layout.html) | +| **chips** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/chips/README.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/chip.html) | | **mask** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/directives/mask/README.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/mask.html) | +| **circular progress** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/progressbar/README.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/circular_progress.html) | | **prefix** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/input-group/README.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/input_group.html) | +| **combo** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/combo/README.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/combo.html) | | **radio-group** | Available | | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/radio_button.html#radio-group)| +| **datePicker** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/date-picker/README.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/date_picker.html) | | **ripple** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/directives/ripple/README.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/ripple.html) | +| **dialog** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/dialog/README.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/dialog.html) | | **suffix** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/tree/master/projects/igniteui-angular/src/lib/input-group/README.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/input_group.html) | +| **drop down** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/drop-down/README.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/drop_down.html) | | **text-highlight** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/tree/master/projects/igniteui-angular/src/lib/directives/text-highlight/README.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/texthighlight.html) | +| **expansion-panel** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/expansion-panel/README.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/expansion_panel.html) | | **text-selection** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/tree/master/projects/igniteui-angular/src/lib/directives/text-selection/README.md) | | +| **grid** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/grids/README.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/grid.html) | | **toggle** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/directives/toggle/README.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/toggle.html) | +| **icon** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/icon/README.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/icon.html) | | **tooltip** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/directives/tooltip/README.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/tooltip.html) | +| **input group** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/input-group/README.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/input_group.html) | | *Others* | Status | Docs | | | +| **linear progress** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/tree/master/projects/igniteui-angular/src/lib/progressbar) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/linear_progress.html) | | **Animations** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/animations/README.md) | | +| **list** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/list/README.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/list.html) | | **dataUtil** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/data-operations/README-DATAUTIL.md) | | +| **navbar** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/navbar/README.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/navbar.html) | | **dataContainer** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/data-operations/README-DATACONTAINER.md) | | +| **navigation drawer** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/navigation-drawer/README.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/navdrawer.html) | | | | | | +| **radio** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/radio/README.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/radio_button.html) | | | | | | +| **slider** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/slider/README.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/slider.html) | | | | | | | **snackbar** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/snackbar/README.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/snackbar.html) | | | | | | | **switch** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/switch/README.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/switch.html) | | | | | | | **tabbar** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/tabbar/README.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/tabbar.html) | | | | | | @@ -160,7 +160,7 @@ You can include Ignite UI for Angular in your project as a dependency using the ## Demo Apps & Documentation The [Warehouse Picklist App](https://github.com/IgniteUI/warehouse-js-blocks) demonstrates using several Ignite UI for Angular widgets together to build a modern, mobile app. -The [Crypto Portfolio App](https://igniteui.github.io/crypto-portfolio-app/#/home) is web and mobile application, developed with Ignite UI for Angular most solid components and styled with one of a kind theming engine. +The [Crypto Portfolio App](https://igniteui.github.io/crypto-portfolio-app/#/home) is a web and mobile application, developed with Ignite UI for Angular components and styled with our one of a kind theming engine. To get started with the Data Grid, use the steps in the [grid walk-through](https://www.infragistics.com/angular-samples/components/grid.html). From 826be2343454ef0d377d24a504e68661ffd284f4 Mon Sep 17 00:00:00 2001 From: Diyan Dimitrov <43128948+DiyanDimitrov@users.noreply.github.com> Date: Wed, 12 Dec 2018 14:18:19 +0200 Subject: [PATCH 16/28] Deprecate clearSummaryCache and recalculateSummaries methods (#3380) * fix(summaries): clear summary cache on data set #3379 * fix(summaries): deprecate clearSummaryCache and recalculateSummaries #3379 # Conflicts: # projects/igniteui-angular/src/lib/grids/grid-base.component.ts * fix(summaries): call summaryService.clearSummaryCache #3379 --- .../igniteui-angular/src/lib/grids/README.md | 1 - .../src/lib/grids/column.component.ts | 4 +-- .../src/lib/grids/grid-base.component.ts | 29 ++++++++++++------- .../grids/summaries/grid-summary.service.ts | 8 ++++- .../grid-summaries/grid-summaries.sample.ts | 1 - 5 files changed, 27 insertions(+), 16 deletions(-) diff --git a/projects/igniteui-angular/src/lib/grids/README.md b/projects/igniteui-angular/src/lib/grids/README.md index e59b141aa31..5ae01bba5f6 100644 --- a/projects/igniteui-angular/src/lib/grids/README.md +++ b/projects/igniteui-angular/src/lib/grids/README.md @@ -246,7 +246,6 @@ Here is a list of all public methods exposed by **igx-grid**: |`enableSummaries(expressions: Array)`|Enable summaries for the columns and apply your `customSummary` if it is provided.| |`disableSummaries(fieldName: string)`|Disable summaries for the specified column.| |`disableSummaries(columns: string[])`|Disable summaries for the listed columns.| -|`clearSummaryCache()`|Delete all cached summaries and force recalculation.| |`previousPage()`|Goes to the previous page if paging is enabled and the current page is not the first.| |`nextPage()`|Goes to the next page if paging is enabled and current page is not the last.| |`paginate(page: number)`|Goes to the specified page if paging is enabled. Page indices are 0 based.| diff --git a/projects/igniteui-angular/src/lib/grids/column.component.ts b/projects/igniteui-angular/src/lib/grids/column.component.ts index 8615c3328de..fe7059c031e 100644 --- a/projects/igniteui-angular/src/lib/grids/column.component.ts +++ b/projects/igniteui-angular/src/lib/grids/column.component.ts @@ -162,7 +162,7 @@ export class IgxColumnComponent implements AfterContentInit { this._hasSummary = value; if (this.grid) { - this.grid.recalculateSummaries(); + this.grid.summaryService.recalculateSummaries(); } } /** @@ -468,7 +468,7 @@ export class IgxColumnComponent implements AfterContentInit { if (this.grid) { this.grid.summaryService.removeSummariesCachePerColumn(this.field); (this.grid as any)._summaryPipeTrigger++; - this.grid.recalculateSummaries(); + this.grid.summaryService.recalculateSummaries(); } } /** diff --git a/projects/igniteui-angular/src/lib/grids/grid-base.component.ts b/projects/igniteui-angular/src/lib/grids/grid-base.component.ts index 7a1a4958196..b5a1a1121e9 100644 --- a/projects/igniteui-angular/src/lib/grids/grid-base.component.ts +++ b/projects/igniteui-angular/src/lib/grids/grid-base.component.ts @@ -67,6 +67,7 @@ import { IGridResourceStrings } from '../core/i18n/grid-resources'; import { CurrentResourceStrings } from '../core/i18n/resources'; import { IgxGridSummaryService } from './summaries/grid-summary.service'; import { IgxSummaryRowComponent } from './summaries/summary-row.component'; +import { DeprecateMethod } from '../core/deprecateDecorators'; const MINIMUM_COLUMN_WIDTH = 136; const FILTER_ROW_HEIGHT = 50; @@ -164,6 +165,7 @@ export enum GridSummaryCalculationMode { } export abstract class IgxGridBaseComponent extends DisplayDensityBase implements OnInit, OnDestroy, AfterContentInit, AfterViewInit { + private _data: any[]; /** * An @Input property that lets you fill the `IgxGridComponent` with an array of data. @@ -173,7 +175,14 @@ export abstract class IgxGridBaseComponent extends DisplayDensityBase implements * @memberof IgxGridBaseComponent */ @Input() - public data: any[]; + public get data(): any[] { + return this._data; + } + + public set data(value: any[]) { + this._data = value; + this.summaryService.clearSummaryCache(); + } private _resourceStrings = CurrentResourceStrings.GridResStrings; private _emptyGridMessage = null; @@ -278,7 +287,7 @@ export abstract class IgxGridBaseComponent extends DisplayDensityBase implements this._filteringExpressionsTree = filteringExpressionTreeClone; this.filteringService.refreshExpressions(); - this.clearSummaryCache(); + this.summaryService.clearSummaryCache(); this.markForCheck(); } } @@ -2264,7 +2273,7 @@ export abstract class IgxGridBaseComponent extends DisplayDensityBase implements this.calcRowCheckboxWidth = 0; this.onRowAdded.pipe(takeUntil(this.destroy$)).subscribe((args) => this.refreshGridState(args)); - this.onRowDeleted.pipe(takeUntil(this.destroy$)).subscribe((args) => this.clearSummaryCache(args)); + this.onRowDeleted.pipe(takeUntil(this.destroy$)).subscribe((args) => this.summaryService.clearSummaryCache(args)); this.onFilteringDone.pipe(takeUntil(this.destroy$)).subscribe(() => this.endEdit(true)); this.onColumnMoving.pipe(takeUntil(this.destroy$)).subscribe(() => { this.endEdit(true); @@ -2273,7 +2282,7 @@ export abstract class IgxGridBaseComponent extends DisplayDensityBase implements this.onPagingDone.pipe(takeUntil(this.destroy$)).subscribe(() => this.endEdit(true)); this.onSortingDone.pipe(takeUntil(this.destroy$)).subscribe(() => this.endEdit(true)); this.transactions.onStateUpdate.pipe(takeUntil(this.destroy$)).subscribe(() => { - this.clearSummaryCache(); + this.summaryService.clearSummaryCache(); this._pipeTrigger++; this.markForCheck(); }); @@ -2302,7 +2311,7 @@ export abstract class IgxGridBaseComponent extends DisplayDensityBase implements this.initColumns(this.columnList); diff.forEachAddedItem((record: IterableChangeRecord) => { - this.clearSummaryCache(); + this.summaryService.clearSummaryCache(); this.calculateGridSizes(); this.onColumnInit.emit(record.item); }); @@ -2310,7 +2319,7 @@ export abstract class IgxGridBaseComponent extends DisplayDensityBase implements requestAnimationFrame(() => { diff.forEachRemovedItem((record: IterableChangeRecord) => { // Recalculate Summaries - this.clearSummaryCache(); + this.summaryService.clearSummaryCache(); this.calculateGridSizes(); // Clear Filtering @@ -3296,8 +3305,8 @@ export abstract class IgxGridBaseComponent extends DisplayDensityBase implements /** * @hidden */ + @DeprecateMethod('There is no need to call clearSummaryCache method.The summary cache is cleared automatically when needed.') public clearSummaryCache(args?) { - this.summaryService.clearSummaryCache(args); } /** @@ -3305,7 +3314,7 @@ export abstract class IgxGridBaseComponent extends DisplayDensityBase implements */ public refreshGridState(args?) { this.endEdit(true); - this.clearSummaryCache(args); + this.summaryService.clearSummaryCache(args); } // TODO: We have return values here. Move them to event args ?? @@ -3353,10 +3362,8 @@ export abstract class IgxGridBaseComponent extends DisplayDensityBase implements /** * @hidden */ + @DeprecateMethod('There is no need to call recalculateSummaries method. The summaries are recalculated automatically when needed.') public recalculateSummaries() { - this.summaryService.resetSummaryHeight(); - this.calculateGridHeight(); - this.cdr.detectChanges(); } /** diff --git a/projects/igniteui-angular/src/lib/grids/summaries/grid-summary.service.ts b/projects/igniteui-angular/src/lib/grids/summaries/grid-summary.service.ts index bcab4d211eb..c34f1de90d2 100644 --- a/projects/igniteui-angular/src/lib/grids/summaries/grid-summary.service.ts +++ b/projects/igniteui-angular/src/lib/grids/summaries/grid-summary.service.ts @@ -12,10 +12,16 @@ export class IgxGridSummaryService { public groupingExpressions = []; public retriggerRootPipe = false; + public recalculateSummaries() { + this.resetSummaryHeight(); + this.grid.calculateGridHeight(); + this.grid.cdr.detectChanges(); + } + public clearSummaryCache(args?) { if (!args) { this.summaryCacheMap.clear(); - if (this.grid.rootSummariesEnabled) { + if (this.grid && this.grid.rootSummariesEnabled) { this.retriggerRootPipe = !this.retriggerRootPipe; } return; diff --git a/src/app/grid-summaries/grid-summaries.sample.ts b/src/app/grid-summaries/grid-summaries.sample.ts index b8d14094cda..921d60c93f8 100644 --- a/src/app/grid-summaries/grid-summaries.sample.ts +++ b/src/app/grid-summaries/grid-summaries.sample.ts @@ -376,7 +376,6 @@ export class GridSummaryComponent implements OnInit { updateData() { const d = [].concat(this.data).concat(this.data.slice(0, 15)); this.data = d; - this.grid1.clearSummaryCache(); } viewRecord(aRecord) { } From ee9f33b6bee67b660fa55f4e0f567b69d94701d4 Mon Sep 17 00:00:00 2001 From: HristoP96 Date: Wed, 12 Dec 2018 14:19:43 +0200 Subject: [PATCH 17/28] docs(readme): Remove igx-text-selection. Update Demo and Support sections. --- README.md | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 3855af2148d..29d7902ae1e 100644 --- a/README.md +++ b/README.md @@ -36,13 +36,13 @@ Current list of controls include: | **datePicker** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/date-picker/README.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/date_picker.html) | | **ripple** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/directives/ripple/README.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/ripple.html) | | **dialog** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/dialog/README.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/dialog.html) | | **suffix** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/tree/master/projects/igniteui-angular/src/lib/input-group/README.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/input_group.html) | | **drop down** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/drop-down/README.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/drop_down.html) | | **text-highlight** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/tree/master/projects/igniteui-angular/src/lib/directives/text-highlight/README.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/texthighlight.html) | -| **expansion-panel** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/expansion-panel/README.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/expansion_panel.html) | | **text-selection** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/tree/master/projects/igniteui-angular/src/lib/directives/text-selection/README.md) | | -| **grid** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/grids/README.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/grid.html) | | **toggle** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/directives/toggle/README.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/toggle.html) | -| **icon** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/icon/README.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/icon.html) | | **tooltip** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/directives/tooltip/README.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/tooltip.html) | -| **input group** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/input-group/README.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/input_group.html) | | *Others* | Status | Docs | | | -| **linear progress** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/tree/master/projects/igniteui-angular/src/lib/progressbar) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/linear_progress.html) | | **Animations** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/animations/README.md) | | -| **list** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/list/README.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/list.html) | | **dataUtil** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/data-operations/README-DATAUTIL.md) | | -| **navbar** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/navbar/README.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/navbar.html) | | **dataContainer** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/data-operations/README-DATACONTAINER.md) | | +| **expansion-panel** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/expansion-panel/README.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/expansion_panel.html) | | **toggle** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/directives/toggle/README.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/toggle.html) | +| **grid** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/grids/README.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/grid.html) | | **tooltip** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/directives/tooltip/README.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/tooltip.html) | +| **icon** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/icon/README.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/icon.html) | | *Others* | Status | Docs | | +| **input group** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/input-group/README.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/input_group.html) | | **Animations** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/animations/README.md) | | | +| **linear progress** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/tree/master/projects/igniteui-angular/src/lib/progressbar) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/linear_progress.html) | | **dataUtil** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/data-operations/README-DATAUTIL.md) | | +| **list** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/list/README.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/list.html) | | **dataContainer** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/data-operations/README-DATACONTAINER.md) | | +| **navbar** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/navbar/README.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/navbar.html) | | | | | | | **navigation drawer** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/navigation-drawer/README.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/navdrawer.html) | | | | | | | **radio** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/radio/README.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/radio_button.html) | | | | | | | **slider** | Available | [Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/slider/README.md) | [Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/slider.html) | | | | | | @@ -160,22 +160,20 @@ You can include Ignite UI for Angular in your project as a dependency using the ## Demo Apps & Documentation The [Warehouse Picklist App](https://github.com/IgniteUI/warehouse-js-blocks) demonstrates using several Ignite UI for Angular widgets together to build a modern, mobile app. -The [Crypto Portfolio App](https://igniteui.github.io/crypto-portfolio-app/#/home) is a web and mobile application, developed with Ignite UI for Angular components and styled with our one of a kind theming engine. +The [Crypto Portfolio App](https://github.com/IgniteUI/crypto-portfolio-app) is a web and mobile application, developed with Ignite UI for Angular components and styled with our one of a kind theming engine. -To get started with the Data Grid, use the steps in the [grid walk-through](https://www.infragistics.com/angular-samples/components/grid.html). +To get started with the Data Grid, use the steps in the [grid walk-through](https://www.infragistics.com/products/ignite-ui-angular/angular/components/grid.html). -All help, related API documents and walk-throughs can be found for each control [here](https://www.infragistics.com/angular-samples/components/grid.html). +All help, related API documents and walk-throughs can be found for each control [here](https://www.infragistics.com/products/ignite-ui-angular/angular/components/grid.html). ## Roadmap [Roadmap document](https://github.com/IgniteUI/igniteui-angular/blob/master/ROADMAP.md) ## Support -Developer support is provided as part of the commercial, paid-for license via [Infragistics Forums](https://www.infragistics.com/community/forums/), or via Chat & Phone with a Priority Support license. To acquire a license for paid support or Prioroty Support, please visit this [page](https://www.infragistics.com/how-to-buy/product-pricing#developers). +Developer support is provided as part of the commercial, paid-for license via [Infragistics Forums](https://www.infragistics.com/community/forums/), or via Chat & Phone with a Priority Support license. To acquire a license for paid support or Priority Support, please visit this [page](https://www.infragistics.com/how-to-buy/product-pricing#developers). Community support for open source usage of this product is available at [StackOverflow](https://stackoverflow.com/questions/tagged/ignite-ui-angular). -Infragistics is only successful if you are successful, if you need additional assitance beyond our help documentation, forums or Prioroty Support, we have a full suite of Services offerings, including Angular Training, Application Architecture and Development and full Design Consultation. Click to learn more about our [Services offerings](https://www.infragistics.com/consulting#popular-services). - ## License This project is released under the Apache License, version 2.0. This is a commercial product, requiring a valid paid-for license for commercial use. This product is free to use for non-commercial applications, like non-profits and educational usage. From bf6db4f9a10fa0682c1bc239b0ada7213c99ba57 Mon Sep 17 00:00:00 2001 From: Radko Kolev Date: Wed, 12 Dec 2018 14:55:54 +0200 Subject: [PATCH 18/28] chore(toolbar): removing unneeded variable #3397 --- src/app/grid-toolbar/grid-toolbar-custom.sample.html | 12 ++++++------ src/app/grid-toolbar/grid-toolbar-custom.sample.ts | 7 ++----- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/src/app/grid-toolbar/grid-toolbar-custom.sample.html b/src/app/grid-toolbar/grid-toolbar-custom.sample.html index 17a3c254fbd..2d071792a63 100644 --- a/src/app/grid-toolbar/grid-toolbar-custom.sample.html +++ b/src/app/grid-toolbar/grid-toolbar-custom.sample.html @@ -35,12 +35,12 @@

Toolbar

-
Toolbar -
Column Hiding -
Column Pinning -
Export Excel -
Export CSV -
+
Toolbar +
Column Hiding +
Column Pinning +
Export Excel +
Export CSV +
diff --git a/src/app/grid-toolbar/grid-toolbar-custom.sample.ts b/src/app/grid-toolbar/grid-toolbar-custom.sample.ts index acef5950ef0..a36bcc2dbc5 100644 --- a/src/app/grid-toolbar/grid-toolbar-custom.sample.ts +++ b/src/app/grid-toolbar/grid-toolbar-custom.sample.ts @@ -1,6 +1,6 @@ -import { Component, ViewChild } from '@angular/core'; -import { IgxColumnComponent, IgxGridComponent } from 'igniteui-angular'; +import { Component } from '@angular/core'; +import { IgxColumnComponent } from 'igniteui-angular'; @Component({ selector: 'app-grid-toolbar-custom-sample', @@ -9,9 +9,6 @@ import { IgxColumnComponent, IgxGridComponent } from 'igniteui-angular'; }) export class GridToolbarCustomSampleComponent { - @ViewChild('grid1', { read: IgxGridComponent }) - public igxGrid1: IgxGridComponent; - data = [ { Name: 'Alice', From 93f0076a6e193042067c2541c65698dbd3d997ca Mon Sep 17 00:00:00 2001 From: Slav Karaslavov <33216749+SlavUI@users.noreply.github.com> Date: Wed, 12 Dec 2018 15:18:34 +0200 Subject: [PATCH 19/28] replacing Advance filtering with excel style filtering --- ROADMAP.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ROADMAP.md b/ROADMAP.md index 29e66e44d03..073eedad0d7 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -15,7 +15,7 @@ 1. Hierarchical Grid [issue](https://github.com/IgniteUI/igniteui-angular/issues/827) 2. igxGrid rendering strategies (like record-based rendering) [issue](https://github.com/IgniteUI/igniteui-angular/issues/2384) 3. Auto-complete (inline editable) -4. Advanced Filtering +4. Excel Style Filtering 5. Multi-cell Selection From 93fe4494a16c36ee6860064ff755be98d143e48d Mon Sep 17 00:00:00 2001 From: Simeon Simeonoff Date: Wed, 12 Dec 2018 17:22:02 +0200 Subject: [PATCH 20/28] refactor(themes): add cell active modifier class (#3351) --- .../core/styles/components/grid/_grid-component.scss | 4 ++++ .../lib/core/styles/components/grid/_grid-theme.scss | 10 ++++++++-- .../lib/core/styles/themes/schemas/light/_grid.scss | 7 ++++++- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/projects/igniteui-angular/src/lib/core/styles/components/grid/_grid-component.scss b/projects/igniteui-angular/src/lib/core/styles/components/grid/_grid-component.scss index 0f0d017e370..c71aa920e5c 100644 --- a/projects/igniteui-angular/src/lib/core/styles/components/grid/_grid-component.scss +++ b/projects/igniteui-angular/src/lib/core/styles/components/grid/_grid-component.scss @@ -176,6 +176,10 @@ @extend %igx-grid__td--tree-cell !optional; } + @include e(td, $m: active) { + @extend %grid-cell--active !optional; + } + @include e(td, $m: selected) { @extend %grid-cell--selected !optional; } diff --git a/projects/igniteui-angular/src/lib/core/styles/components/grid/_grid-theme.scss b/projects/igniteui-angular/src/lib/core/styles/components/grid/_grid-theme.scss index 97f935d4672..850282013e2 100644 --- a/projects/igniteui-angular/src/lib/core/styles/components/grid/_grid-theme.scss +++ b/projects/igniteui-angular/src/lib/core/styles/components/grid/_grid-theme.scss @@ -30,6 +30,7 @@ /// @param {String} $pinned-border-width [null] - The border width of the pinned border. /// @param {String} $pinned-border-style [null] - The CSS border style of the pinned border. /// @param {Color} $pinned-border-color [null] - The color of the pinned border. +/// @param {Color} $cell-active-border-color [null] - The border color for the currently active(focused) cell. /// @param {Color} $cell-selected-background [null] - The selected cell background color. /// @param {Color} $cell-selected-text-color [null] - The selected cell text color. /// @param {Color} $resize-line-color [null] - The table header resize line color. @@ -104,6 +105,7 @@ $pinned-border-style: null, $pinned-border-color: null, + $cell-active-border-color: null, $cell-selected-background: null, $cell-selected-text-color: null, $cell-editing-background: null, @@ -333,6 +335,7 @@ pinned-border-style: $pinned-border-style, pinned-border-color: $pinned-border-color, + cell-active-border-color: $cell-active-border-color, cell-selected-background: $cell-selected-background, cell-editing-background: $cell-editing-background, cell-selected-text-color: $cell-selected-text-color, @@ -843,11 +846,14 @@ } %grid-cell--fixed-width { - // position: relative; flex-grow: 0; outline-style: none; } + %grid-cell--active { + box-shadow: inset 0 0 0 1px --var($theme, 'cell-active-border-color'); + } + %grid-cell--selected { color: --var($theme, 'cell-selected-text-color'); background-color: --var($theme, 'cell-selected-background'); @@ -879,7 +885,7 @@ %igx-grid__td--editing { background-color: --var($theme, 'cell-editing-background') !important; - border: rem(2px) solid --var($theme, 'edit-mode-color'); + box-shadow: inset 0 0 0 rem(2px) --var($theme, 'edit-mode-color'); igx-input-group { width: 100%; diff --git a/projects/igniteui-angular/src/lib/core/styles/themes/schemas/light/_grid.scss b/projects/igniteui-angular/src/lib/core/styles/themes/schemas/light/_grid.scss index 17f9c32f63f..d1aba66c6d5 100644 --- a/projects/igniteui-angular/src/lib/core/styles/themes/schemas/light/_grid.scss +++ b/projects/igniteui-angular/src/lib/core/styles/themes/schemas/light/_grid.scss @@ -28,7 +28,8 @@ /// @prop {Number} pinned-border-width [2px] - The border width of the pinned border. /// @prop {String} pinned-border-style [solid] - The CSS border style of the pinned border. /// @prop {Map} pinned-border-color [igx-color: ('grays', 400)] - The color of the pinned border. -/// @prop {Map} cell-selected-background [igx-color: ('grays', 200), hexrgba: #fff] - The selected cell background color. +/// @prop {Map} cell-active-border-color [igx-color: ('secondary', 500)] - The active(focused) cell border color. +/// @prop {Map} cell-selected-background [igx-color: ('grays', 200)] - The selected cell background color. /// @prop {Map} cell-selected-text-color [igx-contrast-color: ('grays', 200)] - The selected cell text color. /// @prop {Map} resize-line-color [igx-color: ('secondary', 500)] - The table header resize line color. /// @prop {Map} grouparea-background [igx-color: ('grays', 100), hexrgba: #fff] - The grid group area background color. @@ -124,6 +125,10 @@ $_light-grid: ( igx-color: ('grays', 400) ), + cell-active-border-color: ( + igx-color: ('secondary', 500) + ), + cell-selected-background: ( igx-color: ('grays', 200), hexrgba: #fff From 87449e0d0b3c8f4ee01d0ff86511dde95f6df97b Mon Sep 17 00:00:00 2001 From: Desislava Dincheva <34240583+ddincheva@users.noreply.github.com> Date: Wed, 12 Dec 2018 17:53:37 +0200 Subject: [PATCH 21/28] GroupBy and Tree Grid summaries enhancements (#3411) * refactor(IgxGridSummaryCell): navigate from last cell to root summary * refactor(IgxGridGroupByRow): navigate to root summaries from last groupbyRow * refactor(IgxGridSummaryCell): navigate from root summary to last body element * refactor(IgxGrid): added cell active style class * test(grid): add summary keybard navigation tests #3162 * test(grid): update for lint #3162 * refactor(SummaryCell): return on arrow down/up in root summary cell * refactor(Summaries): active summary cell should not be changed on ctrl+home/end * fix(summaries): igxFor now correctly builds size cache Closes #3395 * fix(summaries): Ignore falsy values (except 0) in summaries Closes #3377 * refactor(IgxTreeGrid): grid summaries to work with transactions * test(grid): add KB nav tests for summaries #3162 * refactor(IgxGridSummary): igxgrid groupby summaries with transactions * refactor(IgxGridSummaryService): add check when clear summary cache * refactor(IgxGridSummary): prevent scroll on space * chore(GridNavigation): focus last cell on shift+tab from first root summaryCell * test(grid): Update failing tests #3162 * test(grid): remove fs #3162 * test(grid): update failing test #3162 * chore(IgxGridSummaryCell): added summary cell active class * fix(summaries): Add/delete triggers summary pipe. Summary operands now return the number instead of empty array Closes #3405, #3412 * test(grid): Update tests to use correct summaryActive class #3162 * test(summaries): Adjust tests for the new default value of operands Closes #3412 * refactor(SummaryPipe): do not mutate group records data when remove deleted rows * refactor(GridSummary): recalculate child summaries when row added * fix(resizing): updateSizeCache is called only for vertical virt Closes #3420 * fix(summaries): fix summary pipe triggers #3405 * refactor(GridSummary): recalc summaries on child row added * chore(IgxGridSummary): summary position is top recalc summaries on delete * chore(summaries): fix issue with top summary position * fix(grid): Wrong class applied for active style Closes #3351 --- .../lib/directives/for-of/for_of.directive.ts | 53 +- .../src/lib/grids/api.service.ts | 9 +- .../src/lib/grids/cell.component.ts | 13 +- .../src/lib/grids/grid-base.component.ts | 11 +- .../src/lib/grids/grid-navigation.service.ts | 33 +- .../src/lib/grids/grid/cell.spec.ts | 2 +- .../src/lib/grids/grid/grid-summary.spec.ts | 642 +++++++++++++++++- .../src/lib/grids/grid/grid.component.html | 2 +- .../src/lib/grids/grid/grid.summary.pipe.ts | 30 +- .../lib/grids/grid/groupby-row.component.ts | 4 + .../grids/summaries/grid-root-summary.pipe.ts | 2 +- .../grids/summaries/grid-summary.service.ts | 37 +- .../src/lib/grids/summaries/grid-summary.ts | 27 +- .../grids/summaries/summary-cell.component.ts | 48 +- .../grids/tree-grid/tree-grid-api.service.ts | 10 + .../tree-grid/tree-grid-summaries.spec.ts | 38 +- .../grids/tree-grid/tree-grid.component.html | 2 +- .../grids/tree-grid/tree-grid.component.ts | 7 +- .../grids/tree-grid/tree-grid.summary.pipe.ts | 35 +- .../src/lib/test-utils/grid-samples.spec.ts | 11 + .../src/lib/test-utils/helper-utils.spec.ts | 37 +- .../lib/test-utils/template-strings.spec.ts | 20 +- 22 files changed, 948 insertions(+), 125 deletions(-) diff --git a/projects/igniteui-angular/src/lib/directives/for-of/for_of.directive.ts b/projects/igniteui-angular/src/lib/directives/for-of/for_of.directive.ts index 25ebd9112ee..14c01444dff 100644 --- a/projects/igniteui-angular/src/lib/directives/for-of/for_of.directive.ts +++ b/projects/igniteui-angular/src/lib/directives/for-of/for_of.directive.ts @@ -159,7 +159,7 @@ export class IgxForOfDirective implements OnInit, OnChanges, DoCheck, OnDestr protected hvh: ComponentRef; protected _differ: IterableDiffer | null = null; protected _trackByFn: TrackByFunction; - private heightCache = []; + protected heightCache = []; private _adjustToIndex; private get _isScrolledToBottom() { @@ -625,7 +625,7 @@ export class IgxForOfDirective implements OnInit, OnChanges, DoCheck, OnDestr const view = this._embeddedViews[i]; const rNode = view.rootNodes.find((node) => node.nodeType === Node.ELEMENT_NODE); if (rNode) { - const h = Math.max(rNode.offsetHeight, rNode.clientHeight, parseInt(this.igxForItemSize, 10)); + const h = Math.max(rNode.offsetHeight, parseInt(this.igxForItemSize, 10)); const index = this.state.startIndex + i; if (!this.isRemote && !this.igxForOf[index]) { continue; @@ -1164,6 +1164,53 @@ export class IgxGridForOfDirective extends IgxForOfDirective implements On } } + protected initSizesCache(items: any[]): number { + let totalSize = 0; + let size = 0; + const dimension = this.igxForScrollOrientation === 'horizontal' ? + 'width' : 'height'; + let i = 0; + this.sizesCache = []; + this.heightCache = []; + this.sizesCache.push(0); + const count = this.isRemote ? this.totalItemCount : items.length; + for (i; i < count; i++) { + if (dimension === 'height') { + size = parseInt(this.igxForItemSize, 10) || 0; + if (items[i] && items[i].summaries) { + size = items[i].max; + } + this.heightCache.push(size); + } else { + size = parseInt(items[i][dimension], 10) || 0; + } + totalSize += size; + this.sizesCache.push(totalSize); + } + return totalSize; + } + + protected _updateSizeCache() { + if (this.igxForScrollOrientation === 'horizontal') { + this.initSizesCache(this.igxForOf); + return; + } + const scr = this.vh.instance.elementRef.nativeElement; + + const oldHeight = this.heightCache.length > 0 ? this.heightCache.reduce((acc, val) => acc + val) : 0; + const newHeight = this.initSizesCache(this.igxForOf); + + const diff = oldHeight - newHeight; + + // if data has been changed while container is scrolled + // should update scroll top/left according to change so that same startIndex is in view + if (Math.abs(diff) > 0 && scr.scrollTop > 0) { + this.recalcUpdateSizes(); + const offset = parseInt(this.dc.instance._viewContainer.element.nativeElement.style.top, 10); + scr.scrollTop = this.sizesCache[this.state.startIndex] - offset; + } + } + ngDoCheck() { if (this._differ) { const changes = this._differ.diff(this.igxForOf); @@ -1172,7 +1219,7 @@ export class IgxGridForOfDirective extends IgxForOfDirective implements On if (!this.igxForOf) { return; } - this.initSizesCache(this.igxForOf); + this._updateSizeCache(); this._applyChanges(changes); this.cdr.markForCheck(); this._updateScrollOffset(); diff --git a/projects/igniteui-angular/src/lib/grids/api.service.ts b/projects/igniteui-angular/src/lib/grids/api.service.ts index 19da0f5a345..498eeb1b6b0 100644 --- a/projects/igniteui-angular/src/lib/grids/api.service.ts +++ b/projects/igniteui-angular/src/lib/grids/api.service.ts @@ -136,7 +136,6 @@ export class GridBaseAPIService { this.editCellState.delete(gridId); } } else { - const grid = this.get(gridId); this.editCellState.delete(gridId); } } @@ -347,8 +346,8 @@ export class GridBaseAPIService { grid.summaryService.removeSummaries(rowID); } } - grid.summaryService.clearSummaryCache(emittedArgs); if (!grid.rowEditable || !grid.rowInEditMode || grid.rowInEditMode.rowID !== rowID || !grid.transactions.enabled) { + grid.summaryService.clearSummaryCache(emittedArgs); (grid as any)._pipeTrigger++; } } @@ -387,6 +386,7 @@ export class GridBaseAPIService { const index = this.get_row_index_in_data(id, rowID); const currentRowInEditMode = this.get_edit_row_state(id); let oldValue = Object.assign({}, data[index]); + const hasSummarizedColumns = grid.hasSummarizedColumns; if (grid.currentRowState && grid.currentRowState[grid.primaryKey] === rowID || currentRowInEditMode && currentRowInEditMode.rowID === rowID) { oldValue = Object.assign(oldValue, grid.currentRowState); @@ -405,13 +405,16 @@ export class GridBaseAPIService { if (currentRowInEditMode) { grid.transactions.endPending(false); } + if (hasSummarizedColumns) { + grid.summaryService.removeSummaries(emitArgs.rowID); + } this.updateData(grid, rowID, data[index], emitArgs.oldValue, emitArgs.newValue); if (currentGridState.isRowSelected) { grid.selection.deselect_item(id, rowID); const newRowID = (grid.primaryKey) ? emitArgs.newValue[grid.primaryKey] : emitArgs.newValue; grid.selection.select_item(id, newRowID); } - if (grid.hasSummarizedColumns) { + if (hasSummarizedColumns) { grid.summaryService.removeSummaries(rowID); } (grid as any)._pipeTrigger++; diff --git a/projects/igniteui-angular/src/lib/grids/cell.component.ts b/projects/igniteui-angular/src/lib/grids/cell.component.ts index 6edb901f9e7..1d7f2a47a17 100644 --- a/projects/igniteui-angular/src/lib/grids/cell.component.ts +++ b/projects/igniteui-angular/src/lib/grids/cell.component.ts @@ -18,7 +18,6 @@ import { IgxColumnComponent } from './column.component'; import { isNavigationKey, getNodeSizeViaRange, KEYS } from '../core/utils'; import { State } from '../services/index'; import { IgxGridBaseComponent, IGridEditEventArgs } from './grid-base.component'; -import { first } from 'rxjs/operators'; import { DataType } from '../data-operations/data-util'; /** * Providing reference to `IgxGridCellComponent`: @@ -505,7 +504,9 @@ export class IgxGridCellComponent implements OnInit, AfterViewInit { * @memberof IgxGridCellComponent */ public get editValue() { - return this.gridAPI.get_cell_inEditMode(this.gridID).cell.editValue; + if (this.gridAPI.get_cell_inEditMode(this.gridID)) { + return this.gridAPI.get_cell_inEditMode(this.gridID).cell.editValue; + } } public focused = false; protected isSelected = false; @@ -842,12 +843,12 @@ export class IgxGridCellComponent implements OnInit, AfterViewInit { public onKeydownExitEditMode(event) { if (this.column.editable) { - const editableCell = this; + const editableCell = this.gridAPI.get_cell_inEditMode(this.gridID); const args: IGridEditEventArgs = { cellID: editableCell.cellID, rowID: editableCell.cellID.rowID, - oldValue: editableCell.value, - newValue: editableCell.editValue, + oldValue: editableCell.cell.value, + newValue: editableCell.cell.editValue, cancel: false }; this.grid.onCellEditCancel.emit(args); @@ -904,7 +905,7 @@ export class IgxGridCellComponent implements OnInit, AfterViewInit { } const classList = { - 'igx_grid__cell--edit': this.inEditMode, + 'igx-grid__td--active': this.focused, 'igx-grid__td--number': this.gridAPI.should_apply_number_style(this.column), 'igx-grid__td--editing': this.inEditMode, 'igx-grid__td--pinned': this.column.pinned, diff --git a/projects/igniteui-angular/src/lib/grids/grid-base.component.ts b/projects/igniteui-angular/src/lib/grids/grid-base.component.ts index b5a1a1121e9..ea24f56642b 100644 --- a/projects/igniteui-angular/src/lib/grids/grid-base.component.ts +++ b/projects/igniteui-angular/src/lib/grids/grid-base.component.ts @@ -840,7 +840,7 @@ export abstract class IgxGridBaseComponent extends DisplayDensityBase implements set summaryCalculationMode(value) { this._summaryCalculationMode = value; if (this.gridAPI.get(this.id)) { - this.summaryService.summaryHeight = 0; + this.summaryService.resetSummaryHeight(); this.endEdit(true); this.calculateGridHeight(); this.cdr.markForCheck(); @@ -2273,7 +2273,10 @@ export abstract class IgxGridBaseComponent extends DisplayDensityBase implements this.calcRowCheckboxWidth = 0; this.onRowAdded.pipe(takeUntil(this.destroy$)).subscribe((args) => this.refreshGridState(args)); - this.onRowDeleted.pipe(takeUntil(this.destroy$)).subscribe((args) => this.summaryService.clearSummaryCache(args)); + this.onRowDeleted.pipe(takeUntil(this.destroy$)).subscribe((args) => { + this.summaryService.deleteOperation = true; + this.summaryService.clearSummaryCache(args); + }); this.onFilteringDone.pipe(takeUntil(this.destroy$)).subscribe(() => this.endEdit(true)); this.onColumnMoving.pipe(takeUntil(this.destroy$)).subscribe(() => { this.endEdit(true); @@ -3258,8 +3261,6 @@ export abstract class IgxGridBaseComponent extends DisplayDensityBase implements } else { this._summaries(rest[0], false); } - this.calculateGridHeight(); - this.cdr.detectChanges(); } /** @@ -3773,7 +3774,7 @@ export abstract class IgxGridBaseComponent extends DisplayDensityBase implements if (column) { column.hasSummary = hasSummary; if (summaryOperand) { - if (this.rootSummariesEnabled) {this.summaryService.retriggerRootPipe = !this.summaryService.retriggerRootPipe; } + if (this.rootSummariesEnabled) { this.summaryService.retriggerRootPipe++; } column.summaries = summaryOperand; } } 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 5dc971b1660..b451840e246 100644 --- a/projects/igniteui-angular/src/lib/grids/grid-navigation.service.ts +++ b/projects/igniteui-angular/src/lib/grids/grid-navigation.service.ts @@ -2,7 +2,6 @@ import { Injectable } from '@angular/core'; import { IgxGridBaseComponent } from './grid-base.component'; import { first } from 'rxjs/operators'; import { IgxColumnComponent } from './column.component'; -import { IgxGridRowComponent } from './grid/grid-row.component'; enum MoveDirection { LEFT = 'left', @@ -424,6 +423,33 @@ export class IgxGridNavigationService { } } + public goToLastBodyElement() { + const verticalScroll = this.grid.verticalScrollContainer.getVerticalScroll(); + if (verticalScroll.scrollTop === verticalScroll.scrollHeight - this.grid.verticalScrollContainer.igxForContainerSize) { + const rowIndex = this.grid.verticalScrollContainer.igxForOf.length - 1; + const row = this.grid.nativeElement.querySelector(`[data-rowindex="${rowIndex}"]`); + if (row && row.tagName.toLowerCase() === 'igx-grid-groupby-row') { + row.focus(); + return; + } + const isSummary = (row && row.tagName.toLowerCase() === 'igx-grid-summary-row') ? true : false; + this.onKeydownEnd(rowIndex, isSummary); + } else { + this.grid.verticalScrollContainer.scrollTo(this.grid.verticalScrollContainer.igxForOf.length - 1); + this.grid.verticalScrollContainer.onChunkLoad + .pipe(first()).subscribe(() => { + const rowIndex = this.grid.verticalScrollContainer.igxForOf.length - 1; + const row = this.grid.nativeElement.querySelector(`[data-rowindex="${rowIndex}"]`); + if (row && row.tagName.toLowerCase() === 'igx-grid-groupby-row') { + row.focus(); + return; + } + const isSummary = (row && row.tagName.toLowerCase() === 'igx-grid-summary-row') ? true : false; + this.onKeydownEnd(rowIndex, isSummary); + }); + } + } + public performTab(currentRowEl, rowIndex, visibleColumnIndex, isSummaryRow = false) { if (this.grid.unpinnedColumns[this.grid.unpinnedColumns.length - 1].visibleIndex === visibleColumnIndex) { if (this.isRowInEditMode(rowIndex)) { @@ -433,6 +459,10 @@ export class IgxGridNavigationService { const rowEl = this.grid.rowList.find(row => row.index === rowIndex + 1) ? this.grid.rowList.find(row => row.index === rowIndex + 1) : this.grid.summariesRowList.find(row => row.index === rowIndex + 1); + if (rowIndex === this.grid.verticalScrollContainer.igxForOf.length - 1 && this.grid.rootSummariesEnabled) { + this.onKeydownHome(0, true); + return; + } if (rowEl) { this.navigateDown(currentRowEl, rowIndex, 0); } @@ -449,7 +479,6 @@ export class IgxGridNavigationService { } public moveFocusToFilterCell() { - this.grid.rowList.find(row => row instanceof IgxGridRowComponent).cells.first._clearCellSelection(); const columns = this.grid.filteringService.unpinnedFilterableColumns; if (this.isColumnFullyVisible(columns.length - 1)) { this.grid.filteringService.focusFilterCellChip(columns[columns.length - 1], false); diff --git a/projects/igniteui-angular/src/lib/grids/grid/cell.spec.ts b/projects/igniteui-angular/src/lib/grids/grid/cell.spec.ts index 0a876cd2e8e..fbcecb7fbaf 100644 --- a/projects/igniteui-angular/src/lib/grids/grid/cell.spec.ts +++ b/projects/igniteui-angular/src/lib/grids/grid/cell.spec.ts @@ -406,7 +406,7 @@ describe('IgxGrid - Cell component', () => { configureTestSuite(); let fixture; let grid; - const CELL_CLASS_IN_EDIT_MODE = 'igx_grid__cell--edit'; + const CELL_CLASS_IN_EDIT_MODE = 'igx-grid__td--editing'; beforeEach(async() => { fixture = TestBed.createComponent(CellEditingScrollTestComponent); fixture.detectChanges(); diff --git a/projects/igniteui-angular/src/lib/grids/grid/grid-summary.spec.ts b/projects/igniteui-angular/src/lib/grids/grid/grid-summary.spec.ts index a6423f65eec..7afd742d3fe 100644 --- a/projects/igniteui-angular/src/lib/grids/grid/grid-summary.spec.ts +++ b/projects/igniteui-angular/src/lib/grids/grid/grid-summary.spec.ts @@ -2,20 +2,18 @@ import { async, fakeAsync, TestBed, tick } from '@angular/core/testing'; import { By } from '@angular/platform-browser'; import { BrowserAnimationsModule, NoopAnimationsModule } from '@angular/platform-browser/animations'; -import { IgxInputDirective } from '../../directives/input/input.directive'; import { IgxDateSummaryOperand, IgxGridModule, IgxNumberSummaryOperand, IgxSummaryResult } from './index'; import { IgxGridComponent } from './grid.component'; -import { IgxGridAPIService } from './grid-api.service'; -import { UIInteractions, wait } from '../../test-utils/ui-interactions.spec'; +import { wait, UIInteractions } from '../../test-utils/ui-interactions.spec'; import { GridFunctions } from '../../test-utils/grid-functions.spec'; - import { configureTestSuite } from '../../test-utils/configure-suite'; import { ProductsComponent, VirtualSummaryColumnComponent, SummaryColumnComponent, FilteringComponent, - SummarieGroupByComponent + SummarieGroupByComponent, + SummarieGroupByWithScrollsComponent } from '../../test-utils/grid-samples.spec'; import { HelperUtils } from '../../test-utils/helper-utils.spec'; import { SampleTestData } from '../../test-utils/sample-test-data.spec'; @@ -28,6 +26,7 @@ describe('IgxGrid - Summaries', () => { const ITEM_CLASS = 'igx-grid-summary__item'; const SUMMARY_ROW = 'igx-grid-summary-row'; const SUMARRY_CELL = 'igx-grid-summary-cell'; + const DEBOUNCETIME = 30; beforeEach(async(() => { TestBed.configureTestingModule({ @@ -39,7 +38,8 @@ describe('IgxGrid - Summaries', () => { SummaryColumnsWithIdenticalWidthsComponent, FilteringComponent, ColumnGroupFourLevelTestComponent, - SummarieGroupByComponent + SummarieGroupByComponent, + SummarieGroupByWithScrollsComponent ], imports: [BrowserAnimationsModule, IgxGridModule.forRoot(), NoopAnimationsModule] }) @@ -98,7 +98,7 @@ describe('IgxGrid - Summaries', () => { expect(fixture.debugElement.query(By.css(SUMMARY_CLASS))).toBeDefined(); })); - xit('should have correct summaries when there are null and undefined values', fakeAsync(() => { + it('should have correct summaries when there are null and undefined values', () => { const fixture = TestBed.createComponent(FilteringComponent); fixture.detectChanges(); @@ -107,8 +107,6 @@ describe('IgxGrid - Summaries', () => { grid.getColumnByName('Downloads').hasSummary = true; grid.getColumnByName('Released').hasSummary = true; grid.getColumnByName('ReleaseDate').hasSummary = true; - tick(100); - fixture.detectChanges(); const summaryRow = fixture.debugElement.query(By.css(SUMMARY_ROW)); HelperUtils.verifyColumnSummaries(summaryRow, 0, [], []); @@ -119,7 +117,7 @@ describe('IgxGrid - Summaries', () => { const earliest = SampleTestData.timeGenerator.timedelta(SampleTestData.today, 'month', -1).toLocaleString('us', options); const latest = SampleTestData.timeGenerator.timedelta(SampleTestData.today, 'month', 1).toLocaleString('us', options); HelperUtils.verifyColumnSummaries(summaryRow, 4, ['Count', 'Earliest', 'Latest'], ['8', earliest, latest]); - })); + }); it('should properly render custom summaries', () => { const fixture = TestBed.createComponent(CustomSummariesComponent); @@ -136,7 +134,7 @@ describe('IgxGrid - Summaries', () => { const filterResult = gridComp.rowList.length; expect(filterResult).toEqual(0); - HelperUtils.verifyColumnSummaries(summaryRow, 3, ['Count', 'Sum', 'Avg'], ['0', '', '']); + HelperUtils.verifyColumnSummaries(summaryRow, 3, ['Count', 'Sum', 'Avg'], ['0', '0', '0']); }); it(`Should update summary section when the column is outside of the @@ -155,7 +153,7 @@ describe('IgxGrid - Summaries', () => { }); await wait(30); fixture.detectChanges(); - GridFunctions.scrollLeft(grid, 600); + grid.dataRowList.first.virtDirRow.scrollTo(3); await wait(30); fixture.detectChanges(); @@ -164,7 +162,7 @@ describe('IgxGrid - Summaries', () => { ['11', '0', '99,000', '138,004', '12,545.818']); })); - xit('When we have data which is undefined and enable summary per defined column, error should not be thrown', () => { + it('When we have data which is undefined and enable summary per defined column, error should not be thrown', () => { const fixture = TestBed.createComponent(ProductsComponent); fixture.detectChanges(); @@ -182,7 +180,7 @@ describe('IgxGrid - Summaries', () => { }).not.toThrow(); }); - xit('should change custom summaries at runtime', fakeAsync(() => { + it('should change custom summaries at runtime', fakeAsync(() => { const fixture = TestBed.createComponent(CustomSummariesComponent); const grid = fixture.componentInstance.grid1; fixture.detectChanges(); @@ -190,10 +188,12 @@ describe('IgxGrid - Summaries', () => { const summaryRow = fixture.debugElement.query(By.css(SUMMARY_ROW)); HelperUtils.verifyColumnSummaries(summaryRow, 3, ['Count', 'Sum', 'Avg'], ['10', '39,004', '3,900.4']); HelperUtils.verifyColumnSummaries(summaryRow, 4, ['Earliest'], ['5/17/1990']); + HelperUtils.verifyVisbleSummariesHeight(fixture, 3, grid.defaultRowHeight); grid.getColumnByName('UnitsInStock').summaries = fixture.componentInstance.dealsSummaryMinMax; tick(100); fixture.detectChanges(); HelperUtils.verifyColumnSummaries(summaryRow, 3, ['Min', 'Max'], ['0', '20,000']); + HelperUtils.verifyVisbleSummariesHeight(fixture, 2, grid.defaultRowHeight); })); it('should render correct data after hiding one bigger and then one smaller summary when scrolled to the bottom', (async () => { @@ -282,6 +282,7 @@ describe('IgxGrid - Summaries', () => { const summaryRow = fix.debugElement.query(By.css(SUMMARY_ROW)); HelperUtils.verifyColumnSummaries(summaryRow, 3, ['Min', 'Max'], ['0', '20,000']); + HelperUtils.verifyVisbleSummariesHeight(fix, 3, grid.defaultRowHeight); })); it('should have summary per each column that \'hasSummary\'= true', () => { @@ -357,10 +358,10 @@ describe('IgxGrid - Summaries', () => { expect(typeof emptySummaries[3].summaryResult).not.toEqual(null); expect(typeof emptySummaries[4].summaryResult).not.toEqual(null); - expect(emptySummaries[1].summaryResult.length === 0).toBeTruthy(); - expect(emptySummaries[2].summaryResult.length === 0).toBeTruthy(); - expect(emptySummaries[3].summaryResult.length === 0).toBeTruthy(); - expect(emptySummaries[4].summaryResult.length === 0).toBeTruthy(); + expect(emptySummaries[1].summaryResult === 0).toBeTruthy(); + expect(emptySummaries[2].summaryResult === 0).toBeTruthy(); + expect(emptySummaries[3].summaryResult === 0).toBeTruthy(); + expect(emptySummaries[4].summaryResult === 0).toBeTruthy(); }); @@ -416,6 +417,8 @@ describe('IgxGrid - Summaries', () => { expect(fix.debugElement.query(By.css('.igx-grid__summaries'))).toBeNull(); expect(grid.hasSummarizedColumns).toBe(false); })); + + }); }); @@ -453,7 +456,7 @@ describe('IgxGrid - Summaries', () => { HelperUtils.verifyColumnSummaries(summaryRow, 0, [], []); HelperUtils.verifyColumnSummaries(summaryRow, 1, ['Count'], ['0']); HelperUtils.verifyColumnSummaries(summaryRow, 2, ['Count'], ['0']); - HelperUtils.verifyColumnSummaries(summaryRow, 3, ['Count', 'Min', 'Max', 'Sum', 'Avg'], ['0', '', '', '', '']); + HelperUtils.verifyColumnSummaries(summaryRow, 3, ['Count', 'Min', 'Max', 'Sum', 'Avg'], ['0', '0', '0', '0', '0']); HelperUtils.verifyColumnSummaries(summaryRow, 4, ['Count', 'Earliest', 'Latest'], ['0', '', '']); grid.clearFilter(); @@ -682,6 +685,237 @@ describe('IgxGrid - Summaries', () => { })); }); + describe('Keyboard Navigation', () => { + let fix; + let grid: IgxGridComponent; + beforeEach(() => { + fix = TestBed.createComponent(SummarieGroupByWithScrollsComponent); + fix.detectChanges(); + grid = fix.componentInstance.grid; + }); + + it('should be able to select summaries with arrow keys', async () => { + HelperUtils.focusSummaryCell(fix, 0, 0); + + for (let i = 0; i < 5; i++) { + HelperUtils.verifySummaryCellActive(fix, 0, i); + await HelperUtils.moveSummaryCell(fix, 0, i, 'ArrowRight'); + } + + let summaryRow = HelperUtils.getSummaryRowByDataRowIndex(fix, 0); + HelperUtils.verifyColumnSummaries(summaryRow, 4, ['Count', 'Min', 'Max', 'Sum', 'Avg'], ['8', '25', '50', '293', '36.625']); + HelperUtils.verifyColumnSummaries(summaryRow, 5, ['Count'], ['8']); + + for (let i = 5; i > 0; i--) { + HelperUtils.verifySummaryCellActive(fix, 0, i); + await HelperUtils.moveSummaryCell(fix, 0, i, 'ArrowLeft'); + } + + summaryRow = HelperUtils.getSummaryRowByDataRowIndex(fix, 0); + HelperUtils.verifyColumnSummaries(summaryRow, 0, [], []); + HelperUtils.verifyColumnSummaries(summaryRow, 1, ['Count', 'Min', 'Max', 'Sum', 'Avg'], ['8', '17', '847', '2,188', '273.5']); + }); + + it('should be able to select summaries with tab and shift+tab', async () => { + HelperUtils.focusSummaryCell(fix, 0, 0); + + for (let i = 0; i < 5; i++) { + HelperUtils.verifySummaryCellActive(fix, 0, i); + await HelperUtils.moveSummaryCell(fix, 0, i, 'Tab'); + } + + let summaryRow = HelperUtils.getSummaryRowByDataRowIndex(fix, 0); + HelperUtils.verifyColumnSummaries(summaryRow, 4, ['Count', 'Min', 'Max', 'Sum', 'Avg'], ['8', '25', '50', '293', '36.625']); + HelperUtils.verifyColumnSummaries(summaryRow, 5, ['Count'], ['8']); + + for (let i = 5; i > 0; i--) { + HelperUtils.verifySummaryCellActive(fix, 0, i); + await HelperUtils.moveSummaryCell(fix, 0, i, 'Tab', true); + } + summaryRow = HelperUtils.getSummaryRowByDataRowIndex(fix, 0); + HelperUtils.verifyColumnSummaries(summaryRow, 0, [], []); + HelperUtils.verifyColumnSummaries(summaryRow, 1, ['Count', 'Min', 'Max', 'Sum', 'Avg'], ['8', '17', '847', '2,188', '273.5']); + }); + + it('should be able to navigate with Arrow keys and Ctrl', async () => { + HelperUtils.focusSummaryCell(fix, 0, 1); + + await HelperUtils.moveSummaryCell(fix, 0, 1, 'ArrowRight', false, true); + await wait(100); + HelperUtils.verifySummaryCellActive(fix, 0, 5); + let summaryRow = HelperUtils.getSummaryRowByDataRowIndex(fix, 0); + HelperUtils.verifyColumnSummaries(summaryRow, 4, ['Count', 'Min', 'Max', 'Sum', 'Avg'], ['8', '25', '50', '293', '36.625']); + HelperUtils.verifyColumnSummaries(summaryRow, 5, ['Count'], ['8']); + + await HelperUtils.moveSummaryCell(fix, 0, 5, 'ArrowLeft', false, true); + await wait(100); + HelperUtils.verifySummaryCellActive(fix, 0, 0); + summaryRow = HelperUtils.getSummaryRowByDataRowIndex(fix, 0); + HelperUtils.verifyColumnSummaries(summaryRow, 0, [], []); + HelperUtils.verifyColumnSummaries(summaryRow, 1, ['Count', 'Min', 'Max', 'Sum', 'Avg'], ['8', '17', '847', '2,188', '273.5']); + }); + + it('should not change active summary cell when press Arror Down and Up', async () => { + HelperUtils.focusSummaryCell(fix, 0, 1); + + await HelperUtils.moveSummaryCell(fix, 0, 1, 'ArrowDown'); + HelperUtils.verifySummaryCellActive(fix, 0, 1); + + await HelperUtils.moveSummaryCell(fix, 0, 1, 'ArrowUp'); + HelperUtils.verifySummaryCellActive(fix, 0, 1); + }); + + it('Grouping: should be able to select summaries with arrow keys', async () => { + grid.groupBy({ + fieldName: 'ParentID', dir: SortingDirection.Asc, ignoreCase: false + }); + await wait(DEBOUNCETIME); + fix.detectChanges(); + + HelperUtils.focusSummaryCell(fix, 3, 0); + await wait(DEBOUNCETIME); + + for (let i = 0; i < 5; i++) { + HelperUtils.verifySummaryCellActive(fix, 3, i); + await HelperUtils.moveSummaryCell(fix, 3, i, 'ArrowRight'); + } + + let summaryRow = HelperUtils.getSummaryRowByDataRowIndex(fix, 3); + HelperUtils.verifyColumnSummaries(summaryRow, 4, ['Count', 'Min', 'Max', 'Sum', 'Avg'], ['2', '27', '50', '77', '38.5']); + HelperUtils.verifyColumnSummaries(summaryRow, 5, ['Count'], ['2']); + + for (let i = 5; i > 0; i--) { + HelperUtils.verifySummaryCellActive(fix, 3, i); + await HelperUtils.moveSummaryCell(fix, 3, i, 'ArrowLeft'); + } + + summaryRow = HelperUtils.getSummaryRowByDataRowIndex(fix, 3); + HelperUtils.verifyColumnSummaries(summaryRow, 0, [], []); + HelperUtils.verifyColumnSummaries(summaryRow, 1, ['Count', 'Min', 'Max', 'Sum', 'Avg'], ['2', '17', '17', '34', '17']); + }); + + it('Grouping: should not change active summary cell when press cntr+ArrowUp/Down', async () => { + grid.groupBy({ + fieldName: 'ParentID', dir: SortingDirection.Asc, ignoreCase: false + }); + await wait(DEBOUNCETIME); + fix.detectChanges(); + + HelperUtils.focusSummaryCell(fix, 3, 1); + HelperUtils.verifySummaryCellActive(fix, 3, 1); + + await HelperUtils.moveSummaryCell(fix, 3, 1, 'ArrowDown', false, true); + HelperUtils.verifySummaryCellActive(fix, 3, 1); + + await HelperUtils.moveSummaryCell(fix, 3, 1, 'ArrowUp', false, true); + HelperUtils.verifySummaryCellActive(fix, 3, 1); + }); + + it('Grouping: should be able to navigate with Arrow keys Up/Down and Ctrl', async () => { + grid.groupBy({ + fieldName: 'ParentID', dir: SortingDirection.Asc, ignoreCase: false + }); + await wait(DEBOUNCETIME); + fix.detectChanges(); + + HelperUtils.focusSummaryCell(fix, 3, 1); + + await HelperUtils.moveSummaryCell(fix, 3, 1, 'ArrowRight', false, true); + await wait(100); + HelperUtils.verifySummaryCellActive(fix, 3, 5); + let summaryRow = HelperUtils.getSummaryRowByDataRowIndex(fix, 3); + HelperUtils.verifyColumnSummaries(summaryRow, 4, ['Count', 'Min', 'Max', 'Sum', 'Avg'], ['2', '27', '50', '77', '38.5']); + HelperUtils.verifyColumnSummaries(summaryRow, 5, ['Count'], ['2']); + + await HelperUtils.moveSummaryCell(fix, 3, 5, 'ArrowLeft', false, true); + await wait(100); + HelperUtils.verifySummaryCellActive(fix, 3, 0); + summaryRow = HelperUtils.getSummaryRowByDataRowIndex(fix, 3); + HelperUtils.verifyColumnSummaries(summaryRow, 0, [], []); + HelperUtils.verifyColumnSummaries(summaryRow, 1, ['Count', 'Min', 'Max', 'Sum', 'Avg'], ['2', '17', '17', '34', '17']); + }); + + it('Grouping: should not change active summary cell when press CTRL+Home/End ', async () => { + grid.groupBy({ + fieldName: 'ParentID', dir: SortingDirection.Asc, ignoreCase: false + }); + await wait(DEBOUNCETIME); + fix.detectChanges(); + + HelperUtils.focusSummaryCell(fix, 3, 1); + HelperUtils.verifySummaryCellActive(fix, 3, 1); + + await HelperUtils.moveSummaryCell(fix, 3, 1, 'End', false, true); + HelperUtils.verifySummaryCellActive(fix, 3, 1); + + await HelperUtils.moveSummaryCell(fix, 3, 1, 'Home', false, true); + HelperUtils.verifySummaryCellActive(fix, 3, 1); + }); + + it('Grouping: should navigate with Tab key on summary row ', async () => { + grid.groupBy({ + fieldName: 'ParentID', dir: SortingDirection.Asc, ignoreCase: false + }); + await wait(DEBOUNCETIME); + fix.detectChanges(); + + HelperUtils.focusSummaryCell(fix, 3, 0); + + for (let i = 0; i < 5; i++) { + HelperUtils.verifySummaryCellActive(fix, 3, i); + await HelperUtils.moveSummaryCell(fix, 3, i, 'Tab'); + } + + let summaryRow = HelperUtils.getSummaryRowByDataRowIndex(fix, 3); + HelperUtils.verifyColumnSummaries(summaryRow, 4, ['Count', 'Min', 'Max', 'Sum', 'Avg'], ['2', '27', '50', '77', '38.5']); + HelperUtils.verifyColumnSummaries(summaryRow, 5, ['Count'], ['2']); + + for (let i = 5; i > 0; i--) { + HelperUtils.verifySummaryCellActive(fix, 3, i); + await HelperUtils.moveSummaryCell(fix, 3, i, 'Tab', true); + } + summaryRow = HelperUtils.getSummaryRowByDataRowIndex(fix, 3); + HelperUtils.verifyColumnSummaries(summaryRow, 0, [], []); + HelperUtils.verifyColumnSummaries(summaryRow, 1, ['Count', 'Min', 'Max', 'Sum', 'Avg'], ['2', '17', '17', '34', '17']); + }); + + it('Grouping: should navigate with Tab and Shift+Tab key on summary cell to grid cell ', async () => { + grid.groupBy({ + fieldName: 'ParentID', dir: SortingDirection.Asc, ignoreCase: false + }); + await wait(DEBOUNCETIME); + fix.detectChanges(); + + HelperUtils.focusSummaryCell(fix, 3, 0); + await HelperUtils.moveSummaryCell(fix, 3, 0, 'Tab', true); + await wait(100); + + let cell = grid.getCellByColumn(2, 'OnPTO'); + expect(cell.selected).toBe(true); + expect(cell.focused).toBe(true); + + let summaryRow = HelperUtils.getSummaryRowByDataRowIndex(fix, 3); + HelperUtils.verifyColumnSummaries(summaryRow, 4, ['Count', 'Min', 'Max', 'Sum', 'Avg'], ['2', '27', '50', '77', '38.5']); + HelperUtils.verifyColumnSummaries(summaryRow, 5, ['Count'], ['2']); + + UIInteractions.triggerKeyDownEvtUponElem('tab', cell.nativeElement, true); + await wait(DEBOUNCETIME); + fix.detectChanges(); + + HelperUtils.verifySummaryCellActive(fix, 3, 0); + summaryRow = HelperUtils.getSummaryRowByDataRowIndex(fix, 3); + HelperUtils.verifyColumnSummaries(summaryRow, 0, [], []); + HelperUtils.verifyColumnSummaries(summaryRow, 1, ['Count', 'Min', 'Max', 'Sum', 'Avg'], ['2', '17', '17', '34', '17']); + + await HelperUtils.moveSummaryCell(fix, 3, 0, 'ArrowRight', false, true); + await wait(100); + HelperUtils.verifySummaryCellActive(fix, 3, 5); + cell = grid.getCellByColumn(2, 'OnPTO'); + expect(cell.selected).toBe(true); + }); + + }); + describe('Grouping tests: ', () => { let fix; let grid; @@ -692,7 +926,6 @@ describe('IgxGrid - Summaries', () => { grid.groupBy({ fieldName: 'ParentID', dir: SortingDirection.Asc, ignoreCase: false }); - fix.detectChanges(); }); @@ -711,7 +944,7 @@ describe('IgxGrid - Summaries', () => { grid.getColumnByName('ParentID').hasSummary = false; fix.detectChanges(); - HelperUtils.verifyVisbleSummariesHeight(fix, 3, grid.defaultRowHeight ); + HelperUtils.verifyVisbleSummariesHeight(fix, 3, grid.defaultRowHeight); let summaries = HelperUtils.getAllVisbleSummaries(fix); summaries.forEach(summary => { @@ -734,7 +967,7 @@ describe('IgxGrid - Summaries', () => { fix.detectChanges(); expect(HelperUtils.getAllVisbleSummariesLength(fix)).toEqual(5); - HelperUtils.verifyVisbleSummariesHeight(fix, 1, grid.defaultRowHeight ); + HelperUtils.verifyVisbleSummariesHeight(fix, 1, grid.defaultRowHeight); summaries = HelperUtils.getAllVisbleSummaries(fix); summaries.forEach(summary => { HelperUtils.verifyColumnSummaries(summary, 0, [], []); @@ -748,7 +981,7 @@ describe('IgxGrid - Summaries', () => { it('should show/hide summaries when expand/collapse group row', () => { grid.disableSummaries([{ fieldName: 'Age' }, { fieldName: 'ParentID' }, { fieldName: 'HireDate' }]); - fix.detectChanges(); + // fix.detectChanges(); expect(HelperUtils.getAllVisbleSummariesLength(fix)).toEqual(5); const groupRows = grid.groupsRowList.toArray(); @@ -776,7 +1009,7 @@ describe('IgxGrid - Summaries', () => { grid.getColumnByName('ParentID').hasSummary = false; fix.detectChanges(); - HelperUtils.verifyVisbleSummariesHeight(fix, 3, grid.defaultRowHeight ); + HelperUtils.verifyVisbleSummariesHeight(fix, 3, grid.defaultRowHeight); let summaries = HelperUtils.getAllVisbleSummaries(fix); summaries.forEach(summary => { @@ -799,7 +1032,7 @@ describe('IgxGrid - Summaries', () => { fix.detectChanges(); expect(HelperUtils.getAllVisbleSummariesLength(fix)).toEqual(5); - HelperUtils.verifyVisbleSummariesHeight(fix, 1, grid.defaultRowHeight ); + HelperUtils.verifyVisbleSummariesHeight(fix, 1, grid.defaultRowHeight); summaries = HelperUtils.getAllVisbleSummaries(fix); summaries.forEach(summary => { HelperUtils.verifyColumnSummaries(summary, 0, [], []); @@ -811,7 +1044,341 @@ describe('IgxGrid - Summaries', () => { }); }); + it('should be able to change summaryCalculationMode at runtime', () => { + grid.getColumnByName('Age').hasSummary = false; + grid.getColumnByName('ParentID').hasSummary = false; + fix.detectChanges(); + + expect(HelperUtils.getAllVisbleSummariesRowIndexes(fix)).toEqual([0, 3, 6, 11]); + + grid.summaryCalculationMode = 'rootLevelOnly'; + fix.detectChanges(); + + expect(HelperUtils.getAllVisbleSummariesLength(fix)).toEqual(1); + expect(HelperUtils.getAllVisbleSummariesRowIndexes(fix)).toEqual([0]); + + grid.summaryCalculationMode = 'childLevelsOnly'; + fix.detectChanges(); + + expect(HelperUtils.getAllVisbleSummariesLength(fix)).toEqual(3); + expect(HelperUtils.getAllVisbleSummariesRowIndexes(fix)).toEqual([3, 6, 11]); + const summaryRow = HelperUtils.getSummaryRowByDataRowIndex(fix, 0); + expect(summaryRow).toBeNull(); + + grid.summaryCalculationMode = 'rootAndChildLevels'; + fix.detectChanges(); + + expect(HelperUtils.getAllVisbleSummariesLength(fix)).toEqual(4); + expect(HelperUtils.getAllVisbleSummariesRowIndexes(fix)).toEqual([0, 3, 6, 11]); + }); + + it('should remove child summaries when remove grouped column', () => { + grid.clearGrouping('ParentID'); + fix.detectChanges(); + + expect(HelperUtils.getAllVisbleSummariesLength(fix)).toEqual(1); + expect(HelperUtils.getAllVisbleSummariesRowIndexes(fix)).toEqual([0]); + verifyBaseSummaries(fix); + }); + + it('Hiding: should render correct summaries when show/hide a colomn', () => { + grid.getColumnByName('Age').hidden = true; + grid.getColumnByName('ParentID').hidden = true; + fix.detectChanges(); + let summaries = HelperUtils.getAllVisbleSummaries(fix); + summaries.forEach(summary => { + HelperUtils.verifyColumnSummaries(summary, 0, [], []); + HelperUtils.verifyColumnSummaries(summary, 1, ['Count'], []); + HelperUtils.verifyColumnSummaries(summary, 2, ['Count', 'Earliest', 'Latest'], []); + HelperUtils.verifyColumnSummaries(summary, 3, ['Count'], []); + }); + + HelperUtils.verifyVisbleSummariesHeight(fix, 3); + + grid.getColumnByName('Name').hidden = true; + grid.getColumnByName('HireDate').hidden = true; + grid.getColumnByName('OnPTO').hidden = true; + fix.detectChanges(); + expect(HelperUtils.getAllVisbleSummariesLength(fix)).toEqual(0); + + grid.getColumnByName('HireDate').hidden = false; + grid.getColumnByName('OnPTO').hidden = false; + fix.detectChanges(); + + summaries = HelperUtils.getAllVisbleSummaries(fix); + summaries.forEach(summary => { + HelperUtils.verifyColumnSummaries(summary, 0, [], []); + HelperUtils.verifyColumnSummaries(summary, 1, ['Count', 'Earliest', 'Latest'], []); + HelperUtils.verifyColumnSummaries(summary, 2, ['Count'], []); + }); + + HelperUtils.verifyVisbleSummariesHeight(fix, 3); + + let summaryRow = HelperUtils.getSummaryRowByDataRowIndex(fix, 3); + HelperUtils.verifyColumnSummaries(summaryRow, 2, ['Count'], ['2']); + + summaryRow = HelperUtils.getSummaryRowByDataRowIndex(fix, 6); + HelperUtils.verifyColumnSummaries(summaryRow, 2, ['Count'], ['1']); + + summaryRow = HelperUtils.getSummaryRowByDataRowIndex(fix, 0); + HelperUtils.verifyColumnSummaries(summaryRow, 2, ['Count'], ['8']); + }); + + it('Filtering: should render correct summaries when filter', () => { + grid.filter('ID', 12, IgxNumberFilteringOperand.instance().condition('lessThanOrEqualTo')); + fix.detectChanges(); + + expect(HelperUtils.getAllVisbleSummariesLength(fix)).toEqual(2); + let summaryRow = HelperUtils.getSummaryRowByDataRowIndex(fix, 2); + HelperUtils.verifyColumnSummaries(summaryRow, 2, ['Count'], ['1']); + HelperUtils.verifyColumnSummaries(summaryRow, 3, ['Count', 'Earliest', 'Latest'], ['1', 'Dec 18, 2007', 'Dec 18, 2007']); + HelperUtils.verifyColumnSummaries(summaryRow, 4, ['Count', 'Min', 'Max', 'Sum', 'Avg'], ['1', '50', '50', '50', '50']); + + summaryRow = HelperUtils.getSummaryRowByDataRowIndex(fix, 0); + HelperUtils.verifyColumnSummaries(summaryRow, 2, ['Count'], ['1']); + HelperUtils.verifyColumnSummaries(summaryRow, 3, ['Count', 'Earliest', 'Latest'], ['1', 'Dec 18, 2007', 'Dec 18, 2007']); + HelperUtils.verifyColumnSummaries(summaryRow, 4, ['Count', 'Min', 'Max', 'Sum', 'Avg'], ['1', '50', '50', '50', '50']); + + grid.clearFilter(); + fix.detectChanges(); + + verifyBaseSummaries(fix); + verifySummariesForParentID17(fix, 3); + expect(HelperUtils.getAllVisbleSummariesLength(fix)).toEqual(3); + }); + + it('Filtering: should render correct summaries when filter with no results found', () => { + grid.filter('ID', 1, IgxNumberFilteringOperand.instance().condition('lessThanOrEqualTo')); + fix.detectChanges(); + + expect(HelperUtils.getAllVisbleSummariesLength(fix)).toEqual(1); + const summaryRow = HelperUtils.getSummaryRowByDataRowIndex(fix, 0); + HelperUtils.verifyColumnSummaries(summaryRow, 2, ['Count'], ['0']); + HelperUtils.verifyColumnSummaries(summaryRow, 3, ['Count', 'Earliest', 'Latest'], ['0', '', '']); + HelperUtils.verifyColumnSummaries(summaryRow, 4, ['Count', 'Min', 'Max', 'Sum', 'Avg'], ['0', '0', '0', '0', '0']); + + grid.clearFilter(); + fix.detectChanges(); + + verifyBaseSummaries(fix); + verifySummariesForParentID17(fix, 3); + expect(HelperUtils.getAllVisbleSummariesLength(fix)).toEqual(3); + }); + + it('Paging: should render correct summaries when paging is enable and position is buttom', () => { + grid.paging = true; + grid.perPage = 2; + fix.detectChanges(); + + expect(HelperUtils.getAllVisbleSummariesLength(fix)).toEqual(2); + verifyBaseSummaries(fix); + verifySummariesForParentID17(fix, 3); + + grid.page = 1; + fix.detectChanges(); + + expect(HelperUtils.getAllVisbleSummariesLength(fix)).toEqual(2); + verifyBaseSummaries(fix); + verifySummariesForParentID19(fix, 2); + + grid.page = 2; + fix.detectChanges(); + verifySummariesForParentID147(fix, 3); + verifyBaseSummaries(fix); + + grid.page = 0; + fix.detectChanges(); + + const groupRows = grid.groupsRowList.toArray(); + groupRows[0].toggle(); + fix.detectChanges(); + expect(HelperUtils.getAllVisbleSummariesLength(fix)).toEqual(1); + verifyBaseSummaries(fix); + }); + + it('Paging: should render correct summaries when paging is enable and position is top', () => { + grid.paging = true; + grid.perPage = 2; + grid.summaryPosition = 'top'; + fix.detectChanges(); + + grid.page = 1; + fix.detectChanges(); + + expect(HelperUtils.getAllVisbleSummariesLength(fix)).toEqual(3); + verifyBaseSummaries(fix); + verifySummariesForParentID19(fix, 1); + verifySummariesForParentID147(fix, 4); + + grid.page = 2; + fix.detectChanges(); + expect(HelperUtils.getAllVisbleSummariesLength(fix)).toEqual(2); + verifySummariesForParentID147(fix, 1); + verifyBaseSummaries(fix); + }); + + it('CRUD: Add grouped item', () => { + const newRow = { + ID: 777, + ParentID: 17, + Name: 'New Employee', + HireDate: new Date(2019, 3, 3), + Age: 19, + OnPTO: true + }; + grid.addRow(newRow); + fix.detectChanges(); + + let summaryRow = HelperUtils.getSummaryRowByDataRowIndex(fix, 0); + HelperUtils.verifyColumnSummaries(summaryRow, 0, [], []); + HelperUtils.verifyColumnSummaries(summaryRow, 1, ['Count', 'Min', 'Max', 'Sum', 'Avg'], ['9', '17', '847', '2,205', '245']); + HelperUtils.verifyColumnSummaries(summaryRow, 2, ['Count'], ['9']); + HelperUtils.verifyColumnSummaries(summaryRow, 3, ['Count', 'Earliest', 'Latest'], ['9', 'Dec 18, 2007', 'Apr 3, 2019']); + HelperUtils.verifyColumnSummaries(summaryRow, 4, ['Count', 'Min', 'Max', 'Sum', 'Avg'], ['9', '19', '50', '312', '34.667']); + HelperUtils.verifyColumnSummaries(summaryRow, 5, ['Count'], ['9']); + + summaryRow = HelperUtils.getSummaryRowByDataRowIndex(fix, 4); + HelperUtils.verifyColumnSummaries(summaryRow, 0, [], []); + HelperUtils.verifyColumnSummaries(summaryRow, 1, ['Count', 'Min', 'Max', 'Sum', 'Avg'], ['3', '17', '17', '51', '17']); + HelperUtils.verifyColumnSummaries(summaryRow, 2, ['Count'], ['3']); + HelperUtils.verifyColumnSummaries(summaryRow, 3, ['Count', 'Earliest', 'Latest'], ['3', 'Dec 18, 2007', 'Apr 3, 2019']); + HelperUtils.verifyColumnSummaries(summaryRow, 5, ['Count'], ['3']); + }); + + it('CRUD: Add not grouped item', () => { + const newRow = { + ID: 777, + ParentID: 1, + Name: 'New Employee', + HireDate: new Date(2019, 3, 3), + Age: 19, + OnPTO: true + }; + grid.addRow(newRow); + fix.detectChanges(); + + let summaryRow = HelperUtils.getSummaryRowByDataRowIndex(fix, 0); + HelperUtils.verifyColumnSummaries(summaryRow, 0, [], []); + HelperUtils.verifyColumnSummaries(summaryRow, 1, ['Count', 'Min', 'Max', 'Sum', 'Avg'], ['9', '1', '847', '2,189', '243.222']); + HelperUtils.verifyColumnSummaries(summaryRow, 2, ['Count'], ['9']); + HelperUtils.verifyColumnSummaries(summaryRow, 3, ['Count', 'Earliest', 'Latest'], ['9', 'Dec 18, 2007', 'Apr 3, 2019']); + HelperUtils.verifyColumnSummaries(summaryRow, 4, ['Count', 'Min', 'Max', 'Sum', 'Avg'], ['9', '19', '50', '312', '34.667']); + HelperUtils.verifyColumnSummaries(summaryRow, 5, ['Count'], ['9']); + + summaryRow = HelperUtils.getSummaryRowByDataRowIndex(fix, 2); + HelperUtils.verifyColumnSummaries(summaryRow, 0, [], []); + HelperUtils.verifyColumnSummaries(summaryRow, 1, ['Count', 'Min', 'Max', 'Sum', 'Avg'], ['1', '1', '1', '1', '1']); + HelperUtils.verifyColumnSummaries(summaryRow, 2, ['Count'], ['1']); + HelperUtils.verifyColumnSummaries(summaryRow, 5, ['Count'], ['1']); + + verifySummariesForParentID17(fix, 6); + }); + + it('CRUD: delete node', () => { + grid.getColumnByName('Age').hasSummary = false; + grid.getColumnByName('ParentID').hasSummary = false; + grid.getColumnByName('HireDate').hasSummary = false; + fix.detectChanges(); + + grid.deleteRow(grid.getRowByIndex(1).rowID); + fix.detectChanges(); + + let summaryRow = HelperUtils.getSummaryRowByDataRowIndex(fix, 0); + HelperUtils.verifyColumnSummaries(summaryRow, 2, ['Count'], ['7']); + + summaryRow = HelperUtils.getSummaryRowByDataRowIndex(fix, 2); + HelperUtils.verifyColumnSummaries(summaryRow, 0, [], []); + HelperUtils.verifyColumnSummaries(summaryRow, 2, ['Count'], ['1']); + + expect(HelperUtils.getAllVisbleSummariesLength(fix)).toEqual(5); + + grid.deleteRow(grid.getRowByIndex(1).rowID); + fix.detectChanges(); + summaryRow = HelperUtils.getSummaryRowByDataRowIndex(fix, 0); + HelperUtils.verifyColumnSummaries(summaryRow, 2, ['Count'], ['6']); + expect(HelperUtils.getAllVisbleSummariesLength(fix)).toEqual(4); + }); + + it('CRUD: delete all nodes', () => { + grid.deleteRow(grid.getRowByIndex(1).rowID); + grid.deleteRow(grid.getRowByIndex(2).rowID); + grid.deleteRow(grid.getRowByIndex(5).rowID); + grid.deleteRow(grid.getRowByIndex(8).rowID); + fix.detectChanges(); + + let summaryRow = HelperUtils.getSummaryRowByDataRowIndex(fix, 0); + HelperUtils.verifyColumnSummaries(summaryRow, 2, ['Count'], ['4']); + expect(HelperUtils.getAllVisbleSummariesLength(fix)).toEqual(3); + + grid.deleteRow(grid.getRowByIndex(1).rowID); + grid.deleteRow(grid.getRowByIndex(2).rowID); + grid.deleteRow(grid.getRowByIndex(5).rowID); + grid.deleteRow(grid.getRowByIndex(6).rowID); + fix.detectChanges(); + + summaryRow = HelperUtils.getSummaryRowByDataRowIndex(fix, 0); + HelperUtils.verifyColumnSummaries(summaryRow, 2, ['Count'], ['0']); + HelperUtils.verifyColumnSummaries(summaryRow, 3, ['Count', 'Earliest', 'Latest'], ['0', '', '']); + HelperUtils.verifyColumnSummaries(summaryRow, 4, ['Count', 'Min', 'Max', 'Sum', 'Avg'], ['0', '0', '0', '0', '0']); + expect(HelperUtils.getAllVisbleSummariesLength(fix)).toEqual(1); + }); + + it('CRUD: Update node and keep grouping', () => { + const newRow = { + ID: 12, + ParentID: 17, + Name: 'New Employee', + HireDate: new Date(2019, 3, 3), + Age: 19 + }; + grid.getRowByKey(12).update(newRow); + fix.detectChanges(); + + let summaryRow = HelperUtils.getSummaryRowByDataRowIndex(fix, 0); + HelperUtils.verifyColumnSummaries(summaryRow, 0, [], []); + HelperUtils.verifyColumnSummaries(summaryRow, 2, ['Count'], ['8']); + HelperUtils.verifyColumnSummaries(summaryRow, 3, ['Count', 'Earliest', 'Latest'], ['8', 'Jul 19, 2009', 'Apr 3, 2019']); + HelperUtils.verifyColumnSummaries(summaryRow, 4, ['Count', 'Min', 'Max', 'Sum', 'Avg'], ['8', '19', '44', '262', '32.75']); + HelperUtils.verifyColumnSummaries(summaryRow, 5, ['Count'], ['8']); + + summaryRow = HelperUtils.getSummaryRowByDataRowIndex(fix, 3); + HelperUtils.verifyColumnSummaries(summaryRow, 0, [], []); + HelperUtils.verifyColumnSummaries(summaryRow, 2, ['Count'], ['2']); + HelperUtils.verifyColumnSummaries(summaryRow, 3, ['Count', 'Earliest', 'Latest'], ['2', 'Mar 19, 2016', 'Apr 3, 2019']); + HelperUtils.verifyColumnSummaries(summaryRow, 4, ['Count', 'Min', 'Max', 'Sum', 'Avg'], ['2', '19', '27', '46', '23']); + }); + + it('CRUD: Update node and change grouping', () => { + grid.getColumnByName('Age').hasSummary = false; + grid.getColumnByName('ParentID').hasSummary = false; + + const newRow = { + ID: 12, + ParentID: 19, + Name: 'New Employee', + HireDate: new Date(2019, 3, 3), + Age: 19 + }; + grid.getRowByKey(12).update(newRow); + fix.detectChanges(); + + let summaryRow = HelperUtils.getSummaryRowByDataRowIndex(fix, 0); + HelperUtils.verifyColumnSummaries(summaryRow, 0, [], []); + HelperUtils.verifyColumnSummaries(summaryRow, 2, ['Count'], ['8']); + HelperUtils.verifyColumnSummaries(summaryRow, 3, ['Count', 'Earliest', 'Latest'], ['8', 'Jul 19, 2009', 'Apr 3, 2019']); + HelperUtils.verifyColumnSummaries(summaryRow, 5, ['Count'], ['8']); + + summaryRow = HelperUtils.getSummaryRowByDataRowIndex(fix, 2); + HelperUtils.verifyColumnSummaries(summaryRow, 0, [], []); + HelperUtils.verifyColumnSummaries(summaryRow, 2, ['Count'], ['1']); + HelperUtils.verifyColumnSummaries(summaryRow, 3, ['Count', 'Earliest', 'Latest'], ['1', 'Mar 19, 2016', 'Mar 19, 2016']); + + summaryRow = HelperUtils.getSummaryRowByDataRowIndex(fix, 6); + HelperUtils.verifyColumnSummaries(summaryRow, 0, [], []); + HelperUtils.verifyColumnSummaries(summaryRow, 2, ['Count'], ['2']); + HelperUtils.verifyColumnSummaries(summaryRow, 3, ['Count', 'Earliest', 'Latest'], ['2', 'May 4, 2014', 'Apr 3, 2019']); + }); }); function verifyBaseSummaries(fixture) { @@ -834,6 +1401,16 @@ describe('IgxGrid - Summaries', () => { HelperUtils.verifyColumnSummaries(summaryRow, 5, ['Count'], ['1']); } + function verifySummariesForParentID147(fixture, vissibleIndex) { + const summaryRow = HelperUtils.getSummaryRowByDataRowIndex(fixture, vissibleIndex); + HelperUtils.verifyColumnSummaries(summaryRow, 0, [], []); + HelperUtils.verifyColumnSummaries(summaryRow, 1, ['Count', 'Min', 'Max', 'Sum', 'Avg'], ['3', '147', '147', '441', '147']); + HelperUtils.verifyColumnSummaries(summaryRow, 2, ['Count'], ['3']); + HelperUtils.verifyColumnSummaries(summaryRow, 3, ['Count', 'Earliest', 'Latest'], ['3', 'Jul 19, 2009', 'Sep 18, 2014']); + HelperUtils.verifyColumnSummaries(summaryRow, 4, ['Count', 'Min', 'Max', 'Sum', 'Avg'], ['3', '29', '43', '103', '34.333']); + HelperUtils.verifyColumnSummaries(summaryRow, 5, ['Count'], ['3']); + } + function verifySummariesForParentID17(fixture, vissibleIndex) { const summaryRow = HelperUtils.getSummaryRowByDataRowIndex(fixture, vissibleIndex); HelperUtils.verifyColumnSummaries(summaryRow, 0, [], []); @@ -895,13 +1472,16 @@ class DealsSummaryMinMax extends IgxNumberSummaryOperand { } public operate(summaries?: any[]): IgxSummaryResult[] { - const result = super.operate(summaries); - result.push({ - key: 'test', - label: 'Test', - summaryResult: summaries.filter(rec => rec > 10 && rec < 30).length + const result = super.operate(summaries).filter((obj) => { + if (obj.key === 'min' || obj.key === 'max') { + const summaryResult = obj.summaryResult; + // apply formatting to float numbers + if (Number(summaryResult) === summaryResult) { + obj.summaryResult = summaryResult.toLocaleString('en-us', { maximumFractionDigits: 2 }); + } + return obj; + } }); - return result; } } diff --git a/projects/igniteui-angular/src/lib/grids/grid/grid.component.html b/projects/igniteui-angular/src/lib/grids/grid/grid.component.html index 3a65273b1c7..2b606bccbdb 100644 --- a/projects/igniteui-angular/src/lib/grids/grid/grid.component.html +++ b/projects/igniteui-angular/src/lib/grids/grid/grid.component.html @@ -75,7 +75,7 @@ | gridPreGroupBy:groupingExpressions:groupingExpansionState:groupsExpanded:id:pipeTrigger | gridPaging:page:perPage:id:pipeTrigger | gridPostGroupBy:groupingExpressions:groupingExpansionState:groupsExpanded:id:groupsRecords:pipeTrigger - | gridSummary:hasSummarizedColumns:summaryCalculationMode:summaryPosition:id:summaryPipeTrigger" + | gridSummary:hasSummarizedColumns:summaryCalculationMode:summaryPosition:id:pipeTrigger:summaryPipeTrigger" let-rowIndex="index" [igxForScrollOrientation]="'vertical'" [igxForContainerSize]='calcHeight' [igxForItemSize]="rowHeight" #verticalScrollContainer (onChunkPreload)="dataLoading($event)"> diff --git a/projects/igniteui-angular/src/lib/grids/grid/grid.summary.pipe.ts b/projects/igniteui-angular/src/lib/grids/grid/grid.summary.pipe.ts index 2e3b5dd87a1..be861a51a31 100644 --- a/projects/igniteui-angular/src/lib/grids/grid/grid.summary.pipe.ts +++ b/projects/igniteui-angular/src/lib/grids/grid/grid.summary.pipe.ts @@ -23,7 +23,7 @@ export class IgxGridSummaryPipe implements PipeTransform { hasSummary: boolean, summaryCalculationMode: GridSummaryCalculationMode, summaryPosition: GridSummaryPosition, - id: string, pipeTrigger: number): any[] { + id: string, pipeTrigger: number, summaryPipeTrigger: number): any[] { if (!flatData || !hasSummary || summaryCalculationMode === GridSummaryCalculationMode.rootLevelOnly) { return flatData; @@ -36,6 +36,7 @@ export class IgxGridSummaryPipe implements PipeTransform { const recordsWithSummary = []; const lastChildMap = new Map(); const grid: IgxGridComponent = this.gridAPI.get(gridId); + const maxSummaryHeight = grid.summaryService.calcMaxSummaryHeight(); for (let i = 0; i < collection.length; i++) { const record = collection[i]; @@ -57,9 +58,11 @@ export class IgxGridSummaryPipe implements PipeTransform { for (let j = 0; j < groupRecords.length; j++) { const groupRecord = groupRecords[j]; const groupRecordId = this.gridAPI.get_groupBy_record_id(groupRecord); - const summaries = grid.summaryService.calculateSummaries(groupRecordId, groupRecord.records); + const records = this.removeDeletedRecord(grid, groupRecord.records.slice()); + const summaries = grid.summaryService.calculateSummaries(groupRecordId, records); const summaryRecord: ISummaryRecord = { - summaries: summaries + summaries: summaries, + max: maxSummaryHeight }; recordsWithSummary.push(summaryRecord); } @@ -70,9 +73,11 @@ export class IgxGridSummaryPipe implements PipeTransform { } if (summaryPosition === GridSummaryPosition.top) { - const summaries = grid.summaryService.calculateSummaries(recordId, groupByRecord.records); + const records = this.removeDeletedRecord(grid, groupByRecord.records.slice()); + const summaries = grid.summaryService.calculateSummaries(recordId, records); const summaryRecord: ISummaryRecord = { - summaries: summaries + summaries: summaries, + max: maxSummaryHeight }; recordsWithSummary.push(summaryRecord); } else if (summaryPosition === GridSummaryPosition.bottom) { @@ -100,4 +105,19 @@ export class IgxGridSummaryPipe implements PipeTransform { return recordsWithSummary; } + + private removeDeletedRecord(grid, data) { + if (!grid.transactions.enabled) { + return data; + } + const deletedRows = grid.transactions.getTransactionLog().filter(t => t.type === 'delete').map(t => t.id); + deletedRows.forEach(rowID => { + const tempData = grid.primaryKey ? data.map(rec => rec[grid.primaryKey]) : data; + const index = tempData.indexOf(rowID); + if (index !== -1) { + data.splice(index, 1); + } + }); + return data; + } } diff --git a/projects/igniteui-angular/src/lib/grids/grid/groupby-row.component.ts b/projects/igniteui-angular/src/lib/grids/grid/groupby-row.component.ts index 0e3cbae41f0..273af117298 100644 --- a/projects/igniteui-angular/src/lib/grids/grid/groupby-row.component.ts +++ b/projects/igniteui-angular/src/lib/grids/grid/groupby-row.component.ts @@ -223,6 +223,10 @@ export class IgxGridGroupByRowComponent { this.grid.unpinnedColumns[this.grid.unpinnedColumns.length - 1].visibleIndex); } } else { + if (this.index === this.grid.verticalScrollContainer.igxForOf.length - 1 && this.grid.rootSummariesEnabled) { + this.grid.navigation.onKeydownHome(0, true); + return; + } this.grid.navigation.navigateDown(this.nativeElement, this.index, 0); } break; diff --git a/projects/igniteui-angular/src/lib/grids/summaries/grid-root-summary.pipe.ts b/projects/igniteui-angular/src/lib/grids/summaries/grid-root-summary.pipe.ts index 97cd20fb6bb..c757311b45a 100644 --- a/projects/igniteui-angular/src/lib/grids/summaries/grid-root-summary.pipe.ts +++ b/projects/igniteui-angular/src/lib/grids/summaries/grid-root-summary.pipe.ts @@ -10,7 +10,7 @@ export class IgxSummaryDataPipe implements PipeTransform { constructor(private gridAPI: GridBaseAPIService) { } - transform(id: string, trigger: boolean = false) { + transform(id: string, trigger: number = 0) { const summaryService = this.gridAPI.get(id).summaryService; return summaryService.calculateSummaries( summaryService.rootSummaryID, diff --git a/projects/igniteui-angular/src/lib/grids/summaries/grid-summary.service.ts b/projects/igniteui-angular/src/lib/grids/summaries/grid-summary.service.ts index c34f1de90d2..aef4ecad9b7 100644 --- a/projects/igniteui-angular/src/lib/grids/summaries/grid-summary.service.ts +++ b/projects/igniteui-angular/src/lib/grids/summaries/grid-summary.service.ts @@ -1,5 +1,7 @@ import { Injectable} from '@angular/core'; import { IgxSummaryResult } from './grid-summary'; +import { DataUtil } from '../../data-operations/data-util'; +import { cloneArray } from '../../core/utils'; /** @hidden */ @Injectable() @@ -10,7 +12,8 @@ export class IgxGridSummaryService { public summaryHeight = 0; public maxSummariesLenght = 0; public groupingExpressions = []; - public retriggerRootPipe = false; + public retriggerRootPipe = 0; + public deleteOperation = false; public recalculateSummaries() { this.resetSummaryHeight(); @@ -19,10 +22,11 @@ export class IgxGridSummaryService { } public clearSummaryCache(args?) { + if (!this.summaryCacheMap.size) { return; } if (!args) { this.summaryCacheMap.clear(); if (this.grid && this.grid.rootSummariesEnabled) { - this.retriggerRootPipe = !this.retriggerRootPipe; + this.retriggerRootPipe++; } return; } @@ -33,7 +37,7 @@ export class IgxGridSummaryService { } this.removeSummaries(rowID); } - if (args.rowID) { + if (args.rowID !== undefined && args.rowID !== null) { const columnName = args.cellID ? this.grid.columnList.find(col => col.index === args.cellID.columnID).field : undefined; this.removeSummaries(args.rowID, columnName); } @@ -44,6 +48,12 @@ export class IgxGridSummaryService { this.deleteSummaryCache(this.rootSummaryID, columnName); if (this.summaryCacheMap.size === 1 && this.summaryCacheMap.has(this.rootSummaryID)) { return; } if (this.isTreeGrid) { + if (this.grid.transactions.enabled && this.deleteOperation) { + this.deleteOperation = false; + // TODO: this.removeChildRowSummaries(rowID, columnName); + this.summaryCacheMap.clear(); + return; + } this.removeAllTreeGridSummaries(rowID, columnName); } else { const summaryIds = this.getSummaryID(rowID, this.grid.groupingExpressions); @@ -59,7 +69,7 @@ export class IgxGridSummaryService { cache.delete(columnName); } }); - if (this.grid.rootSummariesEnabled) { this.retriggerRootPipe = !this.retriggerRootPipe; } + if (this.grid.rootSummariesEnabled) { this.retriggerRootPipe++; } } public calcMaxSummaryHeight() { @@ -100,8 +110,9 @@ export class IgxGridSummaryService { public resetSummaryHeight() { this.summaryHeight = 0; + (this.grid as any)._summaryPipeTrigger++; if (this.grid.rootSummariesEnabled) { - this.retriggerRootPipe = !this.retriggerRootPipe; + this.retriggerRootPipe++; } } @@ -133,7 +144,7 @@ export class IgxGridSummaryService { this.summaryCacheMap.delete(id); } if (id === this.rootSummaryID && this.grid.rootSummariesEnabled) { - this.retriggerRootPipe = !this.retriggerRootPipe; + this.retriggerRootPipe++; } } } @@ -141,7 +152,15 @@ export class IgxGridSummaryService { private getSummaryID(rowID, groupingExpressions) { if (groupingExpressions.length === 0) { return []; } const summaryIDs = []; - const rowData = this.grid.primaryKey ? this.grid.getRowByKey(rowID).rowData : rowID; + let data = this.grid.data; + if (this.grid.transactions.enabled) { + data = DataUtil.mergeTransactions( + cloneArray(this.grid.data), + this.grid.transactions.getAggregatedChanges(true), + this.grid.primaryKey + ); + } + const rowData = this.grid.primaryKey ? data.find(rec => rec[this.grid.primaryKey] === rowID) : rowID; let id = '{ '; groupingExpressions.forEach(expr => { id += `'${expr.fieldName}': '${rowData[expr.fieldName]}'`; @@ -162,6 +181,10 @@ export class IgxGridSummaryService { } } + // TODO: remove only deleted rows + private removeChildRowSummaries(rowID, columnName?) { + } + private compareGroupingExpressions(current, groupingArgs) { const newExpressions = groupingArgs.expressions.map(record => record.fieldName); const removedCols = groupingArgs.ungroupedColumns; diff --git a/projects/igniteui-angular/src/lib/grids/summaries/grid-summary.ts b/projects/igniteui-angular/src/lib/grids/summaries/grid-summary.ts index 9275a78e038..aadddca685e 100644 --- a/projects/igniteui-angular/src/lib/grids/summaries/grid-summary.ts +++ b/projects/igniteui-angular/src/lib/grids/summaries/grid-summary.ts @@ -10,9 +10,14 @@ export interface IgxSummaryResult { export interface ISummaryRecord { summaries: Map; + max?: number; cellIndentation?: number; } +const clear = (el) => el === 0 || Boolean(el); +const first = (arr) => arr[0]; +const last = (arr) => arr[arr.length - 1]; + export class IgxSummaryOperand { /** * Counts all the records in the data source. @@ -22,7 +27,7 @@ export class IgxSummaryOperand { * ``` * @memberof IgxSummaryOperand */ - public static count(data: any[]): any { + public static count(data: any[]): number { return data.length; } /** @@ -73,8 +78,8 @@ export class IgxNumberSummaryOperand extends IgxSummaryOperand { * ``` * @memberof IgxNumberSummaryOperand */ - public static min(data: any[]): any { - return data.length ? data.reduce((a, b) => Math.min(a, b)) : []; + public static min(data: any[]): number { + return data.length ? data.filter(clear).reduce((a, b) => Math.min(a, b)) : 0; } /** * Returns the maximum numeric value in the provided data records. @@ -84,8 +89,8 @@ export class IgxNumberSummaryOperand extends IgxSummaryOperand { * ``` * @memberof IgxNumberSummaryOperand */ - public static max(data: any[]): any { - return data.length ? data.reduce((a, b) => Math.max(a, b)) : []; + public static max(data: any[]): number { + return data.length ? data.filter(clear).reduce((a, b) => Math.max(a, b)) : 0; } /** * Returns the sum of the numeric values in the provided data records. @@ -95,8 +100,8 @@ export class IgxNumberSummaryOperand extends IgxSummaryOperand { * ``` * @memberof IgxNumberSummaryOperand */ - public static sum(data: any[]): any { - return data.length ? data.reduce((a, b) => +a + +b) : []; + public static sum(data: any[]): number { + return data.length ? data.filter(clear).reduce((a, b) => +a + +b) : 0; } /** * Returns the average numeric value in the data provided data records. @@ -106,8 +111,8 @@ export class IgxNumberSummaryOperand extends IgxSummaryOperand { * ``` * @memberof IgxNumberSummaryOperand */ - public static average(data: any[]): any { - return data.length ? this.sum(data) / this.count(data) : []; + public static average(data: any[]): number { + return data.length ? this.sum(data) / this.count(data) : 0; } /** * Executes the static methods and returns `IgxSummaryResult[]`. @@ -180,7 +185,7 @@ export class IgxDateSummaryOperand extends IgxSummaryOperand { * @memberof IgxDateSummaryOperand */ public static latest(data: any[]) { - return data.sort((a, b) => new Date(b).valueOf() - new Date(a).valueOf())[0]; + return first(data.filter(clear).sort((a, b) => new Date(b).valueOf() - new Date(a).valueOf())); } /** * Returns the earliest date value in the data records. @@ -191,7 +196,7 @@ export class IgxDateSummaryOperand extends IgxSummaryOperand { * @memberof IgxDateSummaryOperand */ public static earliest(data: any[]) { - return data.sort((a, b) => new Date(b).valueOf() - new Date(a).valueOf())[data.length - 1]; + return last(data.filter(clear).sort((a, b) => new Date(b).valueOf() - new Date(a).valueOf())); } /** * Executes the static methods and returns `IgxSummaryResult[]`. diff --git a/projects/igniteui-angular/src/lib/grids/summaries/summary-cell.component.ts b/projects/igniteui-angular/src/lib/grids/summaries/summary-cell.component.ts index 7ab49a61fdd..60119a30d6a 100644 --- a/projects/igniteui-angular/src/lib/grids/summaries/summary-cell.component.ts +++ b/projects/igniteui-angular/src/lib/grids/summaries/summary-cell.component.ts @@ -40,7 +40,8 @@ export class IgxSummaryCellComponent { 'igx-grid-summary--compact': this.density === DisplayDensity.compact, 'igx-grid-summary--cosy': this.density === DisplayDensity.cosy, 'igx-grid-summary--pinned': this.column.pinned, - 'igx-grid-summary--pinned-last': this.column.isLastPinned + 'igx-grid-summary--pinned-last': this.column.isLastPinned, + 'igx-grid-summary--active': this.focused }; Object.entries(classList).forEach(([className, value]) => { if (value) { @@ -67,31 +68,44 @@ export class IgxSummaryCellComponent { return `Summary_${this.column.field}`; } - get nativeElement(): any { - return this.element.nativeElement; + private focused; + + @HostListener('focus') + public onFocus() { + this.focused = true; + } + + @HostListener('blur') + public onBlur() { + this.focused = false; } @HostListener('keydown', ['$event']) dispatchEvent(event: KeyboardEvent) { const key = event.key.toLowerCase(); if (!this.isKeySupportedInCell(key)) { return; } - const shift = event.shiftKey; - const ctrl = event.ctrlKey; event.preventDefault(); event.stopPropagation(); - if (this.rowIndex === 0 && - this.grid.unpinnedColumns[this.grid.unpinnedColumns.length - 1].visibleIndex === this.visibleColumnIndex) { - return; + const shift = event.shiftKey; + const ctrl = event.ctrlKey; - } - if (ctrl && (key === 'arrowup' || key === 'up' || key === 'down' || key === 'arrowdown')) { return; } + if (ctrl && (key === 'arrowup' || key === 'up' || key === 'down' || key === 'end' || key === 'home')) { return; } const row = this.getRowElementByIndex(this.rowIndex); switch (key) { case 'tab': if (shift) { + if (this.rowIndex === 0 && this.visibleColumnIndex === 0 && this.grid.data && this.grid.data.length) { + this.grid.navigation.goToLastBodyElement(); + return; + } this.grid.navigation.performShiftTabKey(row, this.rowIndex, this.visibleColumnIndex, true); break; } + if (this.rowIndex === 0 && + this.grid.unpinnedColumns[this.grid.unpinnedColumns.length - 1].visibleIndex === this.visibleColumnIndex) { + return; + + } this.grid.navigation.performTab(row, this.rowIndex, this.visibleColumnIndex, true); break; case 'arrowleft': @@ -114,11 +128,15 @@ export class IgxSummaryCellComponent { break; case 'arrowup': case 'up': - this.grid.navigation.navigateUp(row, this.rowIndex, this.visibleColumnIndex); + if (this.rowIndex !== 0) { + this.grid.navigation.navigateUp(row, this.rowIndex, this.visibleColumnIndex); + } break; case 'arrowdown': case 'down': - this.grid.navigation.navigateDown(row, this.rowIndex, this.visibleColumnIndex); + if (this.rowIndex !== 0) { + this.grid.navigation.navigateDown(row, this.rowIndex, this.visibleColumnIndex); + } break; } } @@ -145,6 +163,10 @@ export class IgxSummaryCellComponent { } } + get nativeElement(): any { + return this.element.nativeElement; + } + get isLastUnpinned() { const unpinnedColumns = this.grid.unpinnedColumns; return unpinnedColumns[unpinnedColumns.length - 1] === this.column; @@ -168,7 +190,7 @@ export class IgxSummaryCellComponent { private isKeySupportedInCell(key) { return ['down', 'up', 'left', 'right', 'arrowdown', 'arrowup', 'arrowleft', 'arrowright', - 'home', 'end', 'tab'].indexOf(key) !== -1; + 'home', 'end', 'tab', 'space', ' ', 'spacebar'].indexOf(key) !== -1; } } diff --git a/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid-api.service.ts b/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid-api.service.ts index 5d40a660714..0f18d7236bd 100644 --- a/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid-api.service.ts +++ b/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid-api.service.ts @@ -19,6 +19,16 @@ export class IgxTreeGridAPIService extends GridBaseAPIService row.isFilteredOutParent === undefined || row.isFilteredOutParent === false) .map(rec => rec.data); + if (grid.transactions.enabled) { + const deletedRows = grid.transactions.getTransactionLog().filter(t => t.type === TransactionType.DELETE).map(t => t.id); + deletedRows.forEach(rowID => { + const tempData = grid.primaryKey ? data.map(rec => rec[grid.primaryKey]) : data; + const index = tempData.indexOf(rowID); + if (index !== -1) { + data.splice(index, 1); + } + }); + } return data; } diff --git a/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid-summaries.spec.ts b/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid-summaries.spec.ts index ab2f39b42ec..51d4dcf6cfa 100644 --- a/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid-summaries.spec.ts +++ b/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid-summaries.spec.ts @@ -85,7 +85,7 @@ describe('IgxTreeGrid - Summaries', () => { fix.detectChanges(); verifySummaryForRow317(fix, 5); - expect(HelperUtils.getAllVisbleSummariesLength(fix)).toEqual(4); + expect(HelperUtils.getAllVisbleSummariesLength(fix)).toEqual(3); }); it('should be able to change summaryPosition at runtime', () => { @@ -93,23 +93,23 @@ describe('IgxTreeGrid - Summaries', () => { fix.detectChanges(); verifyTreeBaseSummaries(fix); - expect(HelperUtils.getAllVisbleSummariesLength(fix)).toEqual(5); - expect(HelperUtils.getAllVisbleSummariesRowIndexes(fix)).toEqual([0, 6, 7, 12, 13]); + expect(HelperUtils.getAllVisbleSummariesLength(fix)).toEqual(3); + expect(HelperUtils.getAllVisbleSummariesRowIndexes(fix)).toEqual([0, 6, 7]); treeGrid.summaryPosition = 'top'; fix.detectChanges(); verifyTreeBaseSummaries(fix); - expect(HelperUtils.getAllVisbleSummariesLength(fix)).toEqual(5); + expect(HelperUtils.getAllVisbleSummariesLength(fix)).toEqual(3); - expect(HelperUtils.getAllVisbleSummariesRowIndexes(fix)).toEqual([0, 1, 5, 9, 12]); + expect(HelperUtils.getAllVisbleSummariesRowIndexes(fix)).toEqual([0, 1, 5]); treeGrid.summaryPosition = 'bottom'; fix.detectChanges(); - expect(HelperUtils.getAllVisbleSummariesLength(fix)).toEqual(5); + expect(HelperUtils.getAllVisbleSummariesLength(fix)).toEqual(3); - expect(HelperUtils.getAllVisbleSummariesRowIndexes(fix)).toEqual([0, 6, 7, 12, 13]); + expect(HelperUtils.getAllVisbleSummariesRowIndexes(fix)).toEqual([0, 6, 7]); }); it('should be able to change summaryCalculationMode at runtime', async () => { @@ -117,9 +117,9 @@ describe('IgxTreeGrid - Summaries', () => { fix.detectChanges(); verifyTreeBaseSummaries(fix); - expect(HelperUtils.getAllVisbleSummariesLength(fix)).toEqual(5); + expect(HelperUtils.getAllVisbleSummariesLength(fix)).toEqual(3); - expect(HelperUtils.getAllVisbleSummariesRowIndexes(fix)).toEqual([0, 6, 7, 12, 13]); + expect(HelperUtils.getAllVisbleSummariesRowIndexes(fix)).toEqual([0, 6, 7]); treeGrid.summaryCalculationMode = 'rootLevelOnly'; fix.detectChanges(); @@ -132,8 +132,8 @@ describe('IgxTreeGrid - Summaries', () => { fix.detectChanges(); await wait(50); - expect(HelperUtils.getAllVisbleSummariesLength(fix)).toEqual(5); - expect(HelperUtils.getAllVisbleSummariesRowIndexes(fix)).toEqual([6, 7, 12, 13, 16]); + expect(HelperUtils.getAllVisbleSummariesLength(fix)).toEqual(2); + expect(HelperUtils.getAllVisbleSummariesRowIndexes(fix)).toEqual([6, 7]); const summaryRow = HelperUtils.getSummaryRowByDataRowIndex(fix, 0); expect(summaryRow).toBeNull(); @@ -142,8 +142,8 @@ describe('IgxTreeGrid - Summaries', () => { await wait(50); verifyTreeBaseSummaries(fix); - expect(HelperUtils.getAllVisbleSummariesLength(fix)).toEqual(5); - expect(HelperUtils.getAllVisbleSummariesRowIndexes(fix)).toEqual([0, 6, 7, 12, 13]); + expect(HelperUtils.getAllVisbleSummariesLength(fix)).toEqual(3); + expect(HelperUtils.getAllVisbleSummariesRowIndexes(fix)).toEqual([0, 6, 7]); }); it('should be able to enable/disable summaries at runtime', () => { @@ -192,7 +192,7 @@ describe('IgxTreeGrid - Summaries', () => { HelperUtils.verifyVisbleSummariesHeight(fix, 1); }); - xit('should be able to enable/disable summaries with API', () => { + it('should be able to enable/disable summaries with API', () => { treeGrid.disableSummaries([{ fieldName: 'Age' }, { fieldName: 'HireDate' }]); fix.detectChanges(); @@ -252,13 +252,13 @@ describe('IgxTreeGrid - Summaries', () => { }); summaryRow = HelperUtils.getSummaryRowByDataRowIndex(fix, 4); - HelperUtils.verifyColumnSummaries(summaryRow, 0, ['Count', 'Min', 'Max', 'Sum', 'Avg'], ['3', '29', '43', '103', '34.333']); + HelperUtils.verifyColumnSummaries(summaryRow, 3, ['Count', 'Min', 'Max', 'Sum', 'Avg'], ['3', '29', '43', '103', '34.333']); summaryRow = HelperUtils.getSummaryRowByDataRowIndex(fix, 0); - HelperUtils.verifyColumnSummaries(summaryRow, 0, ['Count', 'Min', 'Max', 'Sum', 'Avg'], ['4', '19', '847', '207', '51.75']); + HelperUtils.verifyColumnSummaries(summaryRow, 3, ['Count', 'Min', 'Max', 'Sum', 'Avg'], ['4', '42', '61', '207', '51.75']); }); - xit('should be able to change summary operant at runtime', () => { + it('should be able to change summary operant at runtime', () => { treeGrid.expandAll(); fix.detectChanges(); @@ -482,7 +482,7 @@ describe('IgxTreeGrid - Summaries', () => { verifySummaryForRow147(fix, 7); }); - xit('CRUD: Add child node', () => { + it('CRUD: Add child node', () => { treeGrid.expandAll(); fix.detectChanges(); @@ -725,7 +725,7 @@ describe('IgxTreeGrid - Summaries', () => { HelperUtils.verifyColumnSummaries(summaryRow, 0, [], []); HelperUtils.verifyColumnSummaries(summaryRow, 1, ['Count'], ['0']); HelperUtils.verifyColumnSummaries(summaryRow, 2, ['Count', 'Earliest', 'Latest'], ['0', '', '']); - HelperUtils.verifyColumnSummaries(summaryRow, 3, ['Count', 'Min', 'Max', 'Sum', 'Avg'], ['0', '', '', '', '']); + HelperUtils.verifyColumnSummaries(summaryRow, 3, ['Count', 'Min', 'Max', 'Sum', 'Avg'], ['0', '0', '0', '0', '0']); HelperUtils.verifyColumnSummaries(summaryRow, 4, ['Count'], ['0']); } diff --git a/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid.component.html b/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid.component.html index 5e9165a74fc..fb5487a9c2e 100644 --- a/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid.component.html +++ b/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid.component.html @@ -53,7 +53,7 @@ | treeGridSorting:sortingExpressions:id:pipeTrigger | treeGridFlattening:id:expansionDepth:expansionStates:pipeTrigger | treeGridPaging:page:perPage:id:pipeTrigger - | treeGridSummary:hasSummarizedColumns:summaryCalculationMode:summaryPosition:id:summaryPipeTrigger" + | treeGridSummary:hasSummarizedColumns:summaryCalculationMode:summaryPosition:id:pipeTrigger:summaryPipeTrigger" let-rowIndex="index" [igxForScrollOrientation]="'vertical'" [igxForContainerSize]='calcHeight' [igxForItemSize]="rowHeight" #verticalScrollContainer (onChunkPreload)="dataLoading($event)"> diff --git a/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid.component.ts b/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid.component.ts index feda02f2e61..dabe80dc71b 100644 --- a/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid.component.ts +++ b/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid.component.ts @@ -351,7 +351,7 @@ export class IgxTreeGridComponent extends IgxGridBaseComponent { if (!parentRecord) { throw Error('Invalid parent row ID!'); } - + this.summaryService.clearSummaryCache({rowID: parentRecord.rowID}); if (this.primaryKey && this.foreignKey) { data[this.foreignKey] = parentRowID; super.addRow(data); @@ -377,7 +377,6 @@ export class IgxTreeGridComponent extends IgxGridBaseComponent { } parentData[childKey].push(data); } - this.onRowAdded.emit({ data }); this._pipeTrigger++; this.cdr.markForCheck(); @@ -385,6 +384,10 @@ export class IgxTreeGridComponent extends IgxGridBaseComponent { this.refreshSearch(); } } else { + if (this.primaryKey && this.foreignKey) { + const rowID = data[this.foreignKey]; + this.summaryService.clearSummaryCache({rowID: rowID}); + } super.addRow(data); } } diff --git a/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid.summary.pipe.ts b/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid.summary.pipe.ts index 2007c18e4d9..a6a50c8fd74 100644 --- a/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid.summary.pipe.ts +++ b/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid.summary.pipe.ts @@ -22,7 +22,7 @@ export class IgxTreeGridSummaryPipe implements PipeTransform { hasSummary: boolean, summaryCalculationMode: GridSummaryCalculationMode, summaryPosition: GridSummaryPosition, - id: string, pipeTrigger: number): any[] { + id: string, pipeTrigger: number, summaryPipeTrigger: number): any[] { const grid: IgxTreeGridComponent = this.gridAPI.get(id); if (!flatData || !hasSummary || summaryCalculationMode === GridSummaryCalculationMode.rootLevelOnly) { @@ -34,6 +34,7 @@ export class IgxTreeGridSummaryPipe implements PipeTransform { private addSummaryRows(grid: IgxTreeGridComponent, collection: ITreeGridRecord[], summaryPosition: GridSummaryPosition): any[] { const recordsWithSummary = []; + const maxSummaryHeight = grid.summaryService.calcMaxSummaryHeight(); for (let i = 0; i < collection.length; i++) { const record = collection[i]; @@ -49,10 +50,12 @@ export class IgxTreeGridSummaryPipe implements PipeTransform { const children = parent.children; if (children[children.length - 1] === childRecord ) { - const childData = children.filter(r => !r.isFilteredOutParent).map(r => r.data); + let childData = children.filter(r => !r.isFilteredOutParent).map(r => r.data); + childData = this.removeDeletedRecord(grid, parent.rowID, childData); const summaries = grid.summaryService.calculateSummaries(parent.rowID, childData); const summaryRecord: ISummaryRecord = { summaries: summaries, + max: maxSummaryHeight, cellIndentation: parent.level + 1 }; recordsWithSummary.push(summaryRecord); @@ -64,10 +67,12 @@ export class IgxTreeGridSummaryPipe implements PipeTransform { } } } else if (summaryPosition === GridSummaryPosition.top && isExpanded) { - const childData = record.children.map(r => r.data); + let childData = record.children.filter(r => !r.isFilteredOutParent).map(r => r.data); + childData = this.removeDeletedRecord(grid, record.rowID, childData); const summaries = grid.summaryService.calculateSummaries(record.rowID, childData); const summaryRecord: ISummaryRecord = { summaries: summaries, + max: maxSummaryHeight, cellIndentation: record.level + 1 }; recordsWithSummary.push(summaryRecord); @@ -76,4 +81,28 @@ export class IgxTreeGridSummaryPipe implements PipeTransform { return recordsWithSummary; } + private removeDeletedRecord(grid, rowId, data) { + if (!grid.transactions.enabled || !grid.cascadeOnDelete) { + return data; + } + const deletedRows = grid.transactions.getTransactionLog().filter(t => t.type === 'delete').map(t => t.id); + let row = grid.records.get(rowId); + if (!row && deletedRows.lenght === 0) { return []; } + row = row.children ? row : row.parent; + while (row) { + rowId = row.rowID; + if (deletedRows.indexOf(rowId) !== -1) { + return []; + } + row = row.parent; + } + deletedRows.forEach(rowID => { + const tempData = grid.primaryKey ? data.map(rec => rec[grid.primaryKey]) : data; + const index = tempData.indexOf(rowID); + if (index !== -1) { + data.splice(index, 1); + } + }); + return data; + } } diff --git a/projects/igniteui-angular/src/lib/test-utils/grid-samples.spec.ts b/projects/igniteui-angular/src/lib/test-utils/grid-samples.spec.ts index 57073e1aab5..95621d5e321 100644 --- a/projects/igniteui-angular/src/lib/test-utils/grid-samples.spec.ts +++ b/projects/igniteui-angular/src/lib/test-utils/grid-samples.spec.ts @@ -753,6 +753,17 @@ export class SummarieGroupByComponent extends BasicGridComponent { public ageSummaryTest = AgeSummaryTest; } +@Component({ + template: `${GridTemplateStrings.declareGrid(`height="800px" width="400px" [primaryKey]="'ID'"`, '', + ColumnDefinitions.summariesGoupByColumns)}` +}) +export class SummarieGroupByWithScrollsComponent extends BasicGridComponent { + public data = SampleTestData.employeeGroupByData(); + public calculationMode = 'rootAndChildLevels'; + public ageSummary = AgeSummary; + public ageSummaryTest = AgeSummaryTest; +} + class AgeSummary extends IgxNumberSummaryOperand { constructor() { super(); diff --git a/projects/igniteui-angular/src/lib/test-utils/helper-utils.spec.ts b/projects/igniteui-angular/src/lib/test-utils/helper-utils.spec.ts index a10a4bad21b..83879fb4385 100644 --- a/projects/igniteui-angular/src/lib/test-utils/helper-utils.spec.ts +++ b/projects/igniteui-angular/src/lib/test-utils/helper-utils.spec.ts @@ -5,6 +5,9 @@ import { wait, UIInteractions } from '../test-utils/ui-interactions.spec'; import { take } from 'rxjs/operators'; import { IgxGridGroupByRowComponent } from '../grids/grid/groupby-row.component'; +const CELL_ACTIVE_CSS_CLASS = 'igx-grid-summary--active'; +const DEBOUNCETIME = 50; + export class HelperUtils { public static getCheckboxElement(name: string, element: DebugElement, fix) { const checkboxElements = element.queryAll(By.css('igx-checkbox')); @@ -154,7 +157,8 @@ export class HelperUtils { }) public static verifyColumnSummaries(summaryRow: DebugElement, summaryIndex: number, summaryLabels, summaryResults) { - const summary = summaryRow.query(By.css('igx-grid-summary-cell[data-visibleindex="' + summaryIndex + '"]')); + // const summary = summaryRow.query(By.css('igx-grid-summary-cell[data-visibleindex="' + summaryIndex + '"]')); + const summary = HelperUtils.getSummaryCellByVisibleIndex(summaryRow, summaryIndex); expect(summary).toBeDefined(); const summaryItems = summary.queryAll(By.css('.igx-grid-summary__item')); if (summaryLabels.length === 0) { @@ -181,6 +185,10 @@ export class HelperUtils { return fix.debugElement.query(By.css('igx-grid-summary-row[data-rowindex="' + rowIndex + '"]')); } + public static getSummaryCellByVisibleIndex(summaryRow: DebugElement, summaryIndex: number) { + return summaryRow.query(By.css('igx-grid-summary-cell[data-visibleindex="' + summaryIndex + '"]')); + } + public static getAllVisbleSummariesLength(fix) { return HelperUtils.getAllVisbleSummaries(fix).length; } @@ -205,4 +213,31 @@ export class HelperUtils { expect(summary.nativeElement.getBoundingClientRect().height).toBeLessThanOrEqual(summariesRows * rowHeight + 1); }); } + + public static verifySummaryCellActive(fix, rowIndex, cellIndex, active: boolean = true) { + const summaryRow = HelperUtils.getSummaryRowByDataRowIndex(fix, rowIndex); + const summ = HelperUtils.getSummaryCellByVisibleIndex(summaryRow, cellIndex); + const hasClass = summ.nativeElement.classList.contains(CELL_ACTIVE_CSS_CLASS); + expect(hasClass === active).toBeTruthy(); + } + + public static moveSummaryCell = + (fix, rowIndex, cellIndex, key, shift = false, ctrl = false) => new Promise(async (resolve, reject) => { + const summaryRow = HelperUtils.getSummaryRowByDataRowIndex(fix, rowIndex); + const summaryCell = HelperUtils.getSummaryCellByVisibleIndex(summaryRow, cellIndex); + summaryCell.nativeElement.dispatchEvent(new KeyboardEvent('keydown', { key: key, shiftKey: shift, ctrlKey: ctrl })); + await wait(DEBOUNCETIME); + fix.detectChanges(); + resolve(); + }) + + public static focusSummaryCell = + (fix, rowIndex, cellIndex) => new Promise(async (resolve, reject) => { + const summaryRow = HelperUtils.getSummaryRowByDataRowIndex(fix, rowIndex); + const summaryCell = HelperUtils.getSummaryCellByVisibleIndex(summaryRow, cellIndex); + summaryCell.nativeElement.dispatchEvent(new Event('focus')); + fix.detectChanges(); + await wait(DEBOUNCETIME); + resolve(); + }) } diff --git a/projects/igniteui-angular/src/lib/test-utils/template-strings.spec.ts b/projects/igniteui-angular/src/lib/test-utils/template-strings.spec.ts index b8098c00029..b64ff56aca3 100644 --- a/projects/igniteui-angular/src/lib/test-utils/template-strings.spec.ts +++ b/projects/igniteui-angular/src/lib/test-utils/template-strings.spec.ts @@ -216,13 +216,13 @@ export class ColumnDefinitions { `; public static productDefaultSummaries = ` - + - + - + - + @@ -392,12 +392,12 @@ export class ColumnDefinitions { `; public static summariesGoupByColumns = ` - - - - - - + + + + + + `; } From f9d2989cab1f717988fce00fea3b83ffe16f4a8d Mon Sep 17 00:00:00 2001 From: Diyan Dimitrov <43128948+DiyanDimitrov@users.noreply.github.com> Date: Wed, 12 Dec 2018 18:05:18 +0200 Subject: [PATCH 22/28] Update summaries in changelog (#3416) * docs(summaries): update summaries in changelog #3414 * docs(summaries): add deprecated methods #3414 * docs(summaries): update readme #3414 * docs(summaries): fix a typo #3414 --- CHANGELOG.md | 7 +++++-- projects/igniteui-angular/src/lib/grids/README.md | 2 ++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d12e3a32af6..1c3ff4f70e0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,9 @@ All notable changes for each version of this project will be documented in this - Allows the developer to easily display a highly templateable message that requires minimal user interaction (1-2 actions) to be dismissed. Read up more information about the IgxBannerComponent in the official [documentation](https://www.infragistics.com/products/ignite-ui-angular/angular/components/banner.html) or the [ReadMe](https://github.com/IgniteUI/igniteui-angular/tree/master/projects/igniteui-angular/src/lib/banner/README.md) - `igxGrid` - Added a new `igxToolbarCustomContent` directive which can be used to mark an `ng-template` which provides a custom content for the IgxGrid's toolbar ([#2983](https://github.com/IgniteUI/igniteui-angular/issues/2983)) + - Summary results are now calculated and displayed by default for each row group when 'Group By' feature is enabled. + - `clearSummaryCache()` and `recalculateSummaries()` methods are deprecated. The grid will clear the cache and recalculate the summaries automatically when needed. + - **Breaking change** `IgxSummaryOperand.operate()` method is called with empty data in order to calculate the necessary height for the summary row. For custom summary operands, the method should always return an array of `IgxSummaryResult` with proper length. - `IgxIconModule`: - **Breaking change** `igxIconService` is now provided in root (providedIn: 'root') and `IgxIconModule.forRoot()` method is deprecated. - **Breaking change** `glyphName` property of the `igxIconComponent` is deprecated. @@ -19,8 +22,8 @@ All notable changes for each version of this project will be documented in this - `focusedValuePipe` input property is provided that allows developers to additionally transform the value on focus; - `IgxTreeGrid`: - Batch editing - an injectable transaction provider accumulates pending changes, which are not directly applied to the grid's data source. Those can later be inspected, manipulated and submitted at once. Changes are collected for individual cells or rows, depending on editing mode, and accumulated per data row/record. - - You can now export the tree grid both to CSV and Excel. - - The hierarchy and the records' expanded states would be reflected in the exported Excel worksheet. + - You can now export the tree grid both to CSV and Excel. The hierarchy and the records' expanded states would be reflected in the exported Excel worksheet. + - Summaries feature is now supported in the tree grid. Summary results are calculated and displayed for the root level and each child level by default. ## 7.0.4 ### Bug fixes diff --git a/projects/igniteui-angular/src/lib/grids/README.md b/projects/igniteui-angular/src/lib/grids/README.md index 5ae01bba5f6..f9e58e5a17c 100644 --- a/projects/igniteui-angular/src/lib/grids/README.md +++ b/projects/igniteui-angular/src/lib/grids/README.md @@ -184,6 +184,8 @@ Below is the list of all inputs that the developers may set to configure the gri |`hideGroupedColumns`| boolean | Determines whether the grouped columns are hidden as well. | |`rowEditable` | boolean | enables/disables row editing mode | |`transactions`| `TransactionService` | Transaction provider allowing access to all transactions and states of the modified rows. | +|`summaryPosition`| GridSummaryPosition | The summary row position for the child levels. The default is top. | +|`summaryCalculationMode`| GridSummaryCalculationMode | The summary calculation mode. The default is rootAndChildLevels, which means summaries are calculated for root and child levels. | ### Outputs From 19b7a777185e9314a71cbd93ef29058ada1df01e Mon Sep 17 00:00:00 2001 From: Aleksandar Kamenov Date: Thu, 13 Dec 2018 10:17:04 +0200 Subject: [PATCH 23/28] chore(*): update header links api docs Closes #3423 --- extras/docs/themes/sassdoc/scss/partials/_header.scss | 6 +++++- extras/docs/themes/sassdoc/views/partials/header.hbs | 2 +- extras/docs/themes/typedoc/src/partials/header.hbs | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/extras/docs/themes/sassdoc/scss/partials/_header.scss b/extras/docs/themes/sassdoc/scss/partials/_header.scss index 01b9759d5eb..ce08e5b0363 100644 --- a/extras/docs/themes/sassdoc/scss/partials/_header.scss +++ b/extras/docs/themes/sassdoc/scss/partials/_header.scss @@ -15,10 +15,14 @@ @include e(logo) { display: flex; align-items: center; - color: #fff; font-size: rem(18); } + @include e(logo-name) { + color: #fff; + text-decoration: none; + } + @include e(logo-version) { font-size: rem(12); background: #666; diff --git a/extras/docs/themes/sassdoc/views/partials/header.hbs b/extras/docs/themes/sassdoc/views/partials/header.hbs index 719ace0cbf4..4ebbba4e909 100644 --- a/extras/docs/themes/sassdoc/views/partials/header.hbs +++ b/extras/docs/themes/sassdoc/views/partials/header.hbs @@ -2,7 +2,7 @@ {{#ifCond lang '==' 'jp'}}{{> infraHeadJA }}{{else}}{{> infraHead }}{{/ifCond}}
diff --git a/extras/docs/themes/typedoc/src/partials/header.hbs b/extras/docs/themes/typedoc/src/partials/header.hbs index 908bbdca1f4..78f1147525b 100644 --- a/extras/docs/themes/typedoc/src/partials/header.hbs +++ b/extras/docs/themes/typedoc/src/partials/header.hbs @@ -3,7 +3,7 @@

- {{project.name}} + {{project.name}} API ver. 7.0.x

From 71184d2b444573cc3d6c617446973cc93d77e40f Mon Sep 17 00:00:00 2001 From: ddincheva Date: Thu, 13 Dec 2018 14:24:56 +0200 Subject: [PATCH 24/28] refactor(IgxGridTemplateOutlet): check if template cache contains destroyed view --- .../template_outlet.directive.ts | 189 +++++++++--------- .../src/lib/grids/grid/grid.search.spec.ts | 6 +- 2 files changed, 100 insertions(+), 95 deletions(-) diff --git a/projects/igniteui-angular/src/lib/directives/template-outlet/template_outlet.directive.ts b/projects/igniteui-angular/src/lib/directives/template-outlet/template_outlet.directive.ts index 0384de3dfb4..972b178ef9a 100644 --- a/projects/igniteui-angular/src/lib/directives/template-outlet/template_outlet.directive.ts +++ b/projects/igniteui-angular/src/lib/directives/template-outlet/template_outlet.directive.ts @@ -1,116 +1,121 @@ import {Directive, EmbeddedViewRef, Input, OnChanges, ChangeDetectorRef, - SimpleChange, SimpleChanges, TemplateRef, ViewContainerRef, NgModule, NgZone, ViewRef, Output, EventEmitter} from '@angular/core'; + SimpleChange, SimpleChanges, TemplateRef, ViewContainerRef, NgModule, NgZone, ViewRef, Output, EventEmitter} from '@angular/core'; import { CommonModule } from '@angular/common'; /** - * @hidden - */ +* @hidden +*/ @Directive({selector: '[igxTemplateOutlet]'}) export class IgxTemplateOutletDirective implements OnChanges { - private _viewRef !: EmbeddedViewRef; +private _viewRef !: EmbeddedViewRef; - /** - * The embedded views cache. Collection is key-value paired. - * Key is the template id, value is the embedded view for the related template. - */ - private _embeddedViewsMap: Map> = new Map(); + /** + * The embedded views cache. Collection is key-value paired. + * Key is the template id, value is the embedded view for the related template. + */ +private _embeddedViewsMap: Map> = new Map(); - @Input() public igxTemplateOutletContext !: Object; +@Input() public igxTemplateOutletContext !: Object; - @Input() public igxTemplateOutlet !: TemplateRef; +@Input() public igxTemplateOutlet !: TemplateRef; - constructor(private _viewContainerRef: ViewContainerRef, private _zone: NgZone, public cdr: ChangeDetectorRef) { - } +constructor(private _viewContainerRef: ViewContainerRef, private _zone: NgZone, public cdr: ChangeDetectorRef) { +} - ngOnChanges(changes: SimpleChanges) { - const recreateView = this._shouldRecreateView(changes); - if (recreateView) { - // view should be re-created due to changes in the template or context. - // check if we have existing view with the new template stored in the cache. - const tmplID = this.igxTemplateOutletContext['templateID']; - const cachedView = tmplID ? - this._embeddedViewsMap.get(tmplID) : - null; - if (!this._viewRef || !cachedView) { - // if view does not exist yet - // or if there is no template defined in the template outlet context - // or if there's no such view in the cache - then re-create view. - this._recreateView(); - } else { - // if view exists, but template has been changed and there is a view in the cache with the related template - // then detach old view and insert the stored one with the matching template - // after that update its context. - this._viewContainerRef.detach(this._viewContainerRef.indexOf(this._viewRef)); - this._viewRef = cachedView; - this._viewContainerRef.insert(this._viewRef, 0); - this._updateExistingContext(this.igxTemplateOutletContext); - } - } else { - // view should not be re-created. Check if it exists and if context exists and just update it. - if (this._viewRef && this.igxTemplateOutletContext) { - this._updateExistingContext(this.igxTemplateOutletContext); - } - } - } +ngOnChanges(changes: SimpleChanges) { + const recreateView = this._shouldRecreateView(changes); + if (recreateView) { + // view should be re-created due to changes in the template or context. + // check if we have existing view with the new template stored in the cache. + const tmplID = this.igxTemplateOutletContext['templateID']; + const cachedView = tmplID ? + this._embeddedViewsMap.get(tmplID) : + null; + if (!this._viewRef || !cachedView) { + // if view does not exist yet + // or if there is no template defined in the template outlet context + // or if there's no such view in the cache - then re-create view. + this._recreateView(); + } else { + // if view exists, but template has been changed and there is a view in the cache with the related template + // then detach old view and insert the stored one with the matching template + // after that update its context. + this._viewContainerRef.detach(this._viewContainerRef.indexOf(this._viewRef)); + if (!cachedView.destroyed) { + this._viewRef = cachedView; + } else { + this._recreateView(); + return; + } + this._viewContainerRef.insert(this._viewRef, 0); + this._updateExistingContext(this.igxTemplateOutletContext); + } + } else { + // view should not be re-created. Check if it exists and if context exists and just update it. + if (this._viewRef && this.igxTemplateOutletContext) { + this._updateExistingContext(this.igxTemplateOutletContext); + } + } +} - private _recreateView() { - // remove and recreate - if (this._viewRef) { - this._viewContainerRef.detach(this._viewContainerRef.indexOf(this._viewRef)); - } - if (this.igxTemplateOutlet) { - this._viewRef = this._viewContainerRef.createEmbeddedView( - this.igxTemplateOutlet, this.igxTemplateOutletContext); - const tmplId = this.igxTemplateOutletContext['templateID']; - if (tmplId) { - // if context contains a template id, check if we have a view for that template already stored in the cache - // if not create a copy and add it to the cache in detached state. - // Note: Views in detached state do not appear in the DOM, however they remain stored in memory. - const res = this._embeddedViewsMap.get(this.igxTemplateOutletContext['templateID']); - if (!res) { - this._embeddedViewsMap.set(this.igxTemplateOutletContext['templateID'], this._viewRef); - } - } - } - } - private _shouldRecreateView(changes: SimpleChanges): boolean { - const ctxChange = changes['igxTemplateOutletContext']; - return !!changes['igxTemplateOutlet'] || (ctxChange && this._hasContextShapeChanged(ctxChange)); - } +private _recreateView() { + // remove and recreate + if (this._viewRef) { + this._viewContainerRef.remove(this._viewContainerRef.indexOf(this._viewRef)); + } + if (this.igxTemplateOutlet) { + this._viewRef = this._viewContainerRef.createEmbeddedView( + this.igxTemplateOutlet, this.igxTemplateOutletContext); + const tmplId = this.igxTemplateOutletContext['templateID']; + if (tmplId) { + // if context contains a template id, check if we have a view for that template already stored in the cache + // if not create a copy and add it to the cache in detached state. + // Note: Views in detached state do not appear in the DOM, however they remain stored in memory. + const res = this._embeddedViewsMap.get(this.igxTemplateOutletContext['templateID']); + if (!res) { + this._embeddedViewsMap.set(this.igxTemplateOutletContext['templateID'], this._viewRef); + } + } + } +} +private _shouldRecreateView(changes: SimpleChanges): boolean { + const ctxChange = changes['igxTemplateOutletContext']; + return !!changes['igxTemplateOutlet'] || (ctxChange && this._hasContextShapeChanged(ctxChange)); +} - private _hasContextShapeChanged(ctxChange: SimpleChange): boolean { - const prevCtxKeys = Object.keys(ctxChange.previousValue || {}); - const currCtxKeys = Object.keys(ctxChange.currentValue || {}); +private _hasContextShapeChanged(ctxChange: SimpleChange): boolean { + const prevCtxKeys = Object.keys(ctxChange.previousValue || {}); + const currCtxKeys = Object.keys(ctxChange.currentValue || {}); - if (prevCtxKeys.length === currCtxKeys.length) { - for (const propName of currCtxKeys) { - if (prevCtxKeys.indexOf(propName) === -1) { - return true; - } - } - return false; - } else { - return true; - } - } + if (prevCtxKeys.length === currCtxKeys.length) { + for (const propName of currCtxKeys) { + if (prevCtxKeys.indexOf(propName) === -1) { + return true; + } + } + return false; + } else { + return true; + } +} - private _updateExistingContext(ctx: Object): void { - for (const propName of Object.keys(ctx)) { - (this._viewRef.context)[propName] = (this.igxTemplateOutletContext)[propName]; - } - } +private _updateExistingContext(ctx: Object): void { + for (const propName of Object.keys(ctx)) { + (this._viewRef.context)[propName] = (this.igxTemplateOutletContext)[propName]; + } +} } /** - * @hidden - */ +* @hidden +*/ @NgModule({ - declarations: [IgxTemplateOutletDirective], - entryComponents: [], - exports: [IgxTemplateOutletDirective], - imports: [CommonModule] + declarations: [IgxTemplateOutletDirective], + entryComponents: [], + exports: [IgxTemplateOutletDirective], + imports: [CommonModule] }) export class IgxTemplateOutletModule { diff --git a/projects/igniteui-angular/src/lib/grids/grid/grid.search.spec.ts b/projects/igniteui-angular/src/lib/grids/grid/grid.search.spec.ts index f62fe23d019..a21d32f7431 100644 --- a/projects/igniteui-angular/src/lib/grids/grid/grid.search.spec.ts +++ b/projects/igniteui-angular/src/lib/grids/grid/grid.search.spec.ts @@ -887,7 +887,7 @@ describe('IgxGrid - search API', () => { expect(highlight).toBe(spans[4]); }); - xit('Should be able to react to changes in grouping', async () => { + it('Should be able to react to changes in grouping', async () => { grid.groupBy({ fieldName: 'JobTitle', dir: SortingDirection.Asc, @@ -943,7 +943,7 @@ describe('IgxGrid - search API', () => { expect(highlight !== null).toBeTruthy(); }); - xit('Should be able to navigate through highlights with grouping and paging enabled', async () => { + it('Should be able to navigate through highlights with grouping and paging enabled', async () => { grid.groupBy({ fieldName: 'JobTitle', dir: SortingDirection.Asc, @@ -988,7 +988,7 @@ describe('IgxGrid - search API', () => { expect(grid.page).toBe(1); }); - xit('Should be able to properly handle perPage changes with gouping and paging', async () => { + it('Should be able to properly handle perPage changes with gouping and paging', async () => { grid.groupBy({ fieldName: 'JobTitle', dir: SortingDirection.Asc, From e2c8be84ba14166e0365f2887e44f505e0ad93d4 Mon Sep 17 00:00:00 2001 From: ddincheva Date: Thu, 13 Dec 2018 14:37:31 +0200 Subject: [PATCH 25/28] chore(IgxTemplateOutlet): fix document formating --- .../template_outlet.directive.ts | 182 +++++++++--------- 1 file changed, 92 insertions(+), 90 deletions(-) diff --git a/projects/igniteui-angular/src/lib/directives/template-outlet/template_outlet.directive.ts b/projects/igniteui-angular/src/lib/directives/template-outlet/template_outlet.directive.ts index 972b178ef9a..c3f0e53519e 100644 --- a/projects/igniteui-angular/src/lib/directives/template-outlet/template_outlet.directive.ts +++ b/projects/igniteui-angular/src/lib/directives/template-outlet/template_outlet.directive.ts @@ -1,121 +1,123 @@ -import {Directive, EmbeddedViewRef, Input, OnChanges, ChangeDetectorRef, - SimpleChange, SimpleChanges, TemplateRef, ViewContainerRef, NgModule, NgZone, ViewRef, Output, EventEmitter} from '@angular/core'; +import { + Directive, EmbeddedViewRef, Input, OnChanges, ChangeDetectorRef, + SimpleChange, SimpleChanges, TemplateRef, ViewContainerRef, NgModule, NgZone, ViewRef, Output, EventEmitter +} from '@angular/core'; import { CommonModule } from '@angular/common'; /** * @hidden */ -@Directive({selector: '[igxTemplateOutlet]'}) +@Directive({ selector: '[igxTemplateOutlet]' }) export class IgxTemplateOutletDirective implements OnChanges { -private _viewRef !: EmbeddedViewRef; + private _viewRef !: EmbeddedViewRef; - /** - * The embedded views cache. Collection is key-value paired. - * Key is the template id, value is the embedded view for the related template. - */ -private _embeddedViewsMap: Map> = new Map(); + /** + * The embedded views cache. Collection is key-value paired. + * Key is the template id, value is the embedded view for the related template. + */ + private _embeddedViewsMap: Map> = new Map(); -@Input() public igxTemplateOutletContext !: Object; + @Input() public igxTemplateOutletContext !: Object; -@Input() public igxTemplateOutlet !: TemplateRef; + @Input() public igxTemplateOutlet !: TemplateRef; -constructor(private _viewContainerRef: ViewContainerRef, private _zone: NgZone, public cdr: ChangeDetectorRef) { -} + constructor(private _viewContainerRef: ViewContainerRef, private _zone: NgZone, public cdr: ChangeDetectorRef) { + } -ngOnChanges(changes: SimpleChanges) { - const recreateView = this._shouldRecreateView(changes); - if (recreateView) { - // view should be re-created due to changes in the template or context. - // check if we have existing view with the new template stored in the cache. - const tmplID = this.igxTemplateOutletContext['templateID']; - const cachedView = tmplID ? - this._embeddedViewsMap.get(tmplID) : - null; - if (!this._viewRef || !cachedView) { - // if view does not exist yet - // or if there is no template defined in the template outlet context - // or if there's no such view in the cache - then re-create view. - this._recreateView(); - } else { + ngOnChanges(changes: SimpleChanges) { + const recreateView = this._shouldRecreateView(changes); + if (recreateView) { + // view should be re-created due to changes in the template or context. + // check if we have existing view with the new template stored in the cache. + const tmplID = this.igxTemplateOutletContext['templateID']; + const cachedView = tmplID ? + this._embeddedViewsMap.get(tmplID) : + null; + if (!this._viewRef || !cachedView) { + // if view does not exist yet + // or if there is no template defined in the template outlet context + // or if there's no such view in the cache - then re-create view. + this._recreateView(); + } else { // if view exists, but template has been changed and there is a view in the cache with the related template // then detach old view and insert the stored one with the matching template // after that update its context. this._viewContainerRef.detach(this._viewContainerRef.indexOf(this._viewRef)); - if (!cachedView.destroyed) { - this._viewRef = cachedView; - } else { - this._recreateView(); - return; - } - this._viewContainerRef.insert(this._viewRef, 0); - this._updateExistingContext(this.igxTemplateOutletContext); - } - } else { - // view should not be re-created. Check if it exists and if context exists and just update it. - if (this._viewRef && this.igxTemplateOutletContext) { - this._updateExistingContext(this.igxTemplateOutletContext); - } - } -} + if (!cachedView.destroyed) { + this._viewRef = cachedView; + } else { + this._recreateView(); + return; + } + this._viewContainerRef.insert(this._viewRef, 0); + this._updateExistingContext(this.igxTemplateOutletContext); + } + } else { + // view should not be re-created. Check if it exists and if context exists and just update it. + if (this._viewRef && this.igxTemplateOutletContext) { + this._updateExistingContext(this.igxTemplateOutletContext); + } + } + } -private _recreateView() { - // remove and recreate - if (this._viewRef) { + private _recreateView() { + // remove and recreate + if (this._viewRef) { this._viewContainerRef.remove(this._viewContainerRef.indexOf(this._viewRef)); - } - if (this.igxTemplateOutlet) { - this._viewRef = this._viewContainerRef.createEmbeddedView( - this.igxTemplateOutlet, this.igxTemplateOutletContext); - const tmplId = this.igxTemplateOutletContext['templateID']; - if (tmplId) { - // if context contains a template id, check if we have a view for that template already stored in the cache - // if not create a copy and add it to the cache in detached state. - // Note: Views in detached state do not appear in the DOM, however they remain stored in memory. - const res = this._embeddedViewsMap.get(this.igxTemplateOutletContext['templateID']); - if (!res) { - this._embeddedViewsMap.set(this.igxTemplateOutletContext['templateID'], this._viewRef); - } - } - } -} -private _shouldRecreateView(changes: SimpleChanges): boolean { - const ctxChange = changes['igxTemplateOutletContext']; - return !!changes['igxTemplateOutlet'] || (ctxChange && this._hasContextShapeChanged(ctxChange)); -} + } + if (this.igxTemplateOutlet) { + this._viewRef = this._viewContainerRef.createEmbeddedView( + this.igxTemplateOutlet, this.igxTemplateOutletContext); + const tmplId = this.igxTemplateOutletContext['templateID']; + if (tmplId) { + // if context contains a template id, check if we have a view for that template already stored in the cache + // if not create a copy and add it to the cache in detached state. + // Note: Views in detached state do not appear in the DOM, however they remain stored in memory. + const res = this._embeddedViewsMap.get(this.igxTemplateOutletContext['templateID']); + if (!res) { + this._embeddedViewsMap.set(this.igxTemplateOutletContext['templateID'], this._viewRef); + } + } + } + } + private _shouldRecreateView(changes: SimpleChanges): boolean { + const ctxChange = changes['igxTemplateOutletContext']; + return !!changes['igxTemplateOutlet'] || (ctxChange && this._hasContextShapeChanged(ctxChange)); + } -private _hasContextShapeChanged(ctxChange: SimpleChange): boolean { - const prevCtxKeys = Object.keys(ctxChange.previousValue || {}); - const currCtxKeys = Object.keys(ctxChange.currentValue || {}); + private _hasContextShapeChanged(ctxChange: SimpleChange): boolean { + const prevCtxKeys = Object.keys(ctxChange.previousValue || {}); + const currCtxKeys = Object.keys(ctxChange.currentValue || {}); - if (prevCtxKeys.length === currCtxKeys.length) { - for (const propName of currCtxKeys) { - if (prevCtxKeys.indexOf(propName) === -1) { - return true; - } - } - return false; - } else { - return true; - } -} + if (prevCtxKeys.length === currCtxKeys.length) { + for (const propName of currCtxKeys) { + if (prevCtxKeys.indexOf(propName) === -1) { + return true; + } + } + return false; + } else { + return true; + } + } -private _updateExistingContext(ctx: Object): void { - for (const propName of Object.keys(ctx)) { - (this._viewRef.context)[propName] = (this.igxTemplateOutletContext)[propName]; - } -} + private _updateExistingContext(ctx: Object): void { + for (const propName of Object.keys(ctx)) { + (this._viewRef.context)[propName] = (this.igxTemplateOutletContext)[propName]; + } + } } /** * @hidden */ @NgModule({ - declarations: [IgxTemplateOutletDirective], - entryComponents: [], - exports: [IgxTemplateOutletDirective], - imports: [CommonModule] + declarations: [IgxTemplateOutletDirective], + entryComponents: [], + exports: [IgxTemplateOutletDirective], + imports: [CommonModule] }) export class IgxTemplateOutletModule { From 8f9cb2d57175bcac935c4d34a79bf44c493d036b Mon Sep 17 00:00:00 2001 From: ddincheva Date: Thu, 13 Dec 2018 14:48:13 +0200 Subject: [PATCH 26/28] chore(*): remove unnecessary typos --- .../template_outlet.directive.ts | 120 +++++++++--------- 1 file changed, 59 insertions(+), 61 deletions(-) diff --git a/projects/igniteui-angular/src/lib/directives/template-outlet/template_outlet.directive.ts b/projects/igniteui-angular/src/lib/directives/template-outlet/template_outlet.directive.ts index c3f0e53519e..8517c71e64a 100644 --- a/projects/igniteui-angular/src/lib/directives/template-outlet/template_outlet.directive.ts +++ b/projects/igniteui-angular/src/lib/directives/template-outlet/template_outlet.directive.ts @@ -1,21 +1,19 @@ -import { - Directive, EmbeddedViewRef, Input, OnChanges, ChangeDetectorRef, - SimpleChange, SimpleChanges, TemplateRef, ViewContainerRef, NgModule, NgZone, ViewRef, Output, EventEmitter -} from '@angular/core'; +import {Directive, EmbeddedViewRef, Input, OnChanges, ChangeDetectorRef, + SimpleChange, SimpleChanges, TemplateRef, ViewContainerRef, NgModule, NgZone, ViewRef, Output, EventEmitter} from '@angular/core'; import { CommonModule } from '@angular/common'; /** -* @hidden -*/ -@Directive({ selector: '[igxTemplateOutlet]' }) + * @hidden + */ +@Directive({selector: '[igxTemplateOutlet]'}) export class IgxTemplateOutletDirective implements OnChanges { private _viewRef !: EmbeddedViewRef; - /** - * The embedded views cache. Collection is key-value paired. - * Key is the template id, value is the embedded view for the related template. - */ + /** + * The embedded views cache. Collection is key-value paired. + * Key is the template id, value is the embedded view for the related template. + */ private _embeddedViewsMap: Map> = new Map(); @Input() public igxTemplateOutletContext !: Object; @@ -23,64 +21,64 @@ export class IgxTemplateOutletDirective implements OnChanges { @Input() public igxTemplateOutlet !: TemplateRef; - constructor(private _viewContainerRef: ViewContainerRef, private _zone: NgZone, public cdr: ChangeDetectorRef) { + constructor(private _viewContainerRef: ViewContainerRef, private _zone: NgZone, public cdr: ChangeDetectorRef) { } ngOnChanges(changes: SimpleChanges) { const recreateView = this._shouldRecreateView(changes); if (recreateView) { - // view should be re-created due to changes in the template or context. - // check if we have existing view with the new template stored in the cache. - const tmplID = this.igxTemplateOutletContext['templateID']; - const cachedView = tmplID ? - this._embeddedViewsMap.get(tmplID) : - null; - if (!this._viewRef || !cachedView) { - // if view does not exist yet - // or if there is no template defined in the template outlet context - // or if there's no such view in the cache - then re-create view. - this._recreateView(); - } else { - // if view exists, but template has been changed and there is a view in the cache with the related template - // then detach old view and insert the stored one with the matching template - // after that update its context. - this._viewContainerRef.detach(this._viewContainerRef.indexOf(this._viewRef)); - if (!cachedView.destroyed) { - this._viewRef = cachedView; + // view should be re-created due to changes in the template or context. + // check if we have existing view with the new template stored in the cache. + const tmplID = this.igxTemplateOutletContext['templateID']; + const cachedView = tmplID ? + this._embeddedViewsMap.get(tmplID) : + null; + if (!this._viewRef || !cachedView) { + // if view does not exist yet + // or if there is no template defined in the template outlet context + // or if there's no such view in the cache - then re-create view. + this._recreateView(); } else { - this._recreateView(); - return; + // if view exists, but template has been changed and there is a view in the cache with the related template + // then detach old view and insert the stored one with the matching template + // after that update its context. + this._viewContainerRef.detach(this._viewContainerRef.indexOf(this._viewRef)); + if (!cachedView.destroyed) { + this._viewRef = cachedView; + } else { + this._recreateView(); + return; + } + this._viewContainerRef.insert(this._viewRef, 0); + this._updateExistingContext(this.igxTemplateOutletContext); } - this._viewContainerRef.insert(this._viewRef, 0); - this._updateExistingContext(this.igxTemplateOutletContext); - } } else { - // view should not be re-created. Check if it exists and if context exists and just update it. + // view should not be re-created. Check if it exists and if context exists and just update it. if (this._viewRef && this.igxTemplateOutletContext) { - this._updateExistingContext(this.igxTemplateOutletContext); + this._updateExistingContext(this.igxTemplateOutletContext); } } } private _recreateView() { - // remove and recreate - if (this._viewRef) { - this._viewContainerRef.remove(this._viewContainerRef.indexOf(this._viewRef)); - } - if (this.igxTemplateOutlet) { - this._viewRef = this._viewContainerRef.createEmbeddedView( - this.igxTemplateOutlet, this.igxTemplateOutletContext); - const tmplId = this.igxTemplateOutletContext['templateID']; - if (tmplId) { - // if context contains a template id, check if we have a view for that template already stored in the cache - // if not create a copy and add it to the cache in detached state. - // Note: Views in detached state do not appear in the DOM, however they remain stored in memory. - const res = this._embeddedViewsMap.get(this.igxTemplateOutletContext['templateID']); - if (!res) { - this._embeddedViewsMap.set(this.igxTemplateOutletContext['templateID'], this._viewRef); - } + // remove and recreate + if (this._viewRef) { + this._viewContainerRef.remove(this._viewContainerRef.indexOf(this._viewRef)); + } + if (this.igxTemplateOutlet) { + this._viewRef = this._viewContainerRef.createEmbeddedView( + this.igxTemplateOutlet, this.igxTemplateOutletContext); + const tmplId = this.igxTemplateOutletContext['templateID']; + if (tmplId) { + // if context contains a template id, check if we have a view for that template already stored in the cache + // if not create a copy and add it to the cache in detached state. + // Note: Views in detached state do not appear in the DOM, however they remain stored in memory. + const res = this._embeddedViewsMap.get(this.igxTemplateOutletContext['templateID']); + if (!res) { + this._embeddedViewsMap.set(this.igxTemplateOutletContext['templateID'], this._viewRef); + } + } } - } } private _shouldRecreateView(changes: SimpleChanges): boolean { const ctxChange = changes['igxTemplateOutletContext']; @@ -106,18 +104,18 @@ export class IgxTemplateOutletDirective implements OnChanges { private _updateExistingContext(ctx: Object): void { for (const propName of Object.keys(ctx)) { (this._viewRef.context)[propName] = (this.igxTemplateOutletContext)[propName]; - } + } } } /** -* @hidden -*/ + * @hidden + */ @NgModule({ - declarations: [IgxTemplateOutletDirective], - entryComponents: [], - exports: [IgxTemplateOutletDirective], - imports: [CommonModule] + declarations: [IgxTemplateOutletDirective], + entryComponents: [], + exports: [IgxTemplateOutletDirective], + imports: [CommonModule] }) export class IgxTemplateOutletModule { From eedd17da59ea6d5b31840ee06cfddae6a22636fe Mon Sep 17 00:00:00 2001 From: Damyan Petev Date: Thu, 13 Dec 2018 16:46:40 +0200 Subject: [PATCH 27/28] fix(tree-grid,batch-edit): `generateRowPath` proper path order, cleanup #3439 --- .../src/lib/grids/tree-grid/tree-grid-api.service.ts | 2 +- .../src/lib/grids/tree-grid/tree-grid.component.ts | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid-api.service.ts b/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid-api.service.ts index 0f18d7236bd..f13afc43a8c 100644 --- a/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid-api.service.ts +++ b/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid-api.service.ts @@ -158,7 +158,7 @@ export class IgxTreeGridAPIService extends GridBaseAPIService Date: Thu, 13 Dec 2018 17:22:39 +0200 Subject: [PATCH 28/28] Focus native element on expansion indicator focus (#3435) * fix(tree-grid): focus native element on indicator focus #3434 * fix(tree-grid): focus selected cell after expand #3437 * fix(tree-grid): remove some obsolete code #3437 --- .../grids/tree-grid/tree-cell.component.html | 2 +- .../grids/tree-grid/tree-cell.component.ts | 4 +-- .../grids/tree-grid/tree-grid-api.service.ts | 29 +++++++------------ 3 files changed, 13 insertions(+), 22 deletions(-) diff --git a/projects/igniteui-angular/src/lib/grids/tree-grid/tree-cell.component.html b/projects/igniteui-angular/src/lib/grids/tree-grid/tree-cell.component.html index 77dc101da33..785ee533a03 100644 --- a/projects/igniteui-angular/src/lib/grids/tree-grid/tree-cell.component.html +++ b/projects/igniteui-angular/src/lib/grids/tree-grid/tree-cell.component.html @@ -30,7 +30,7 @@
+ (click)="toggle($event)" (focus)="onIndicatorFocus()" tabindex="-1"> chevron_right expand_more
diff --git a/projects/igniteui-angular/src/lib/grids/tree-grid/tree-cell.component.ts b/projects/igniteui-angular/src/lib/grids/tree-grid/tree-cell.component.ts index 18a4ebac380..df95138361f 100644 --- a/projects/igniteui-angular/src/lib/grids/tree-grid/tree-cell.component.ts +++ b/projects/igniteui-angular/src/lib/grids/tree-grid/tree-cell.component.ts @@ -68,9 +68,9 @@ export class IgxTreeGridCellComponent extends IgxGridCellComponent { /** * @hidden */ - public onIndicatorFocus(event: Event) { + public onIndicatorFocus() { this.gridAPI.submit_value(this.gridID); - this.onFocus(event); + this.nativeElement.focus(); } /** diff --git a/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid-api.service.ts b/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid-api.service.ts index 0f18d7236bd..7da876713b8 100644 --- a/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid-api.service.ts +++ b/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid-api.service.ts @@ -86,32 +86,23 @@ export class IgxTreeGridAPIService extends GridBaseAPIService= 0); - const isScrolledToBottom = grid.rowList.length > 0 && grid.rowList.last.index === - grid.verticalScrollContainer.igxForOf.length - 1; const expandedStates = grid.expansionStates; expandedStates.set(row.rowID, expanded); grid.expansionStates = expandedStates; - if (isScrolledToBottom) { - grid.nativeElement.focus({preventScroll: true}); - grid.verticalScrollContainer.onChunkLoad - .pipe(first()) - .subscribe(() => { - grid.nativeElement.querySelector( - `[data-rowIndex="${groupRowIndex}"][data-visibleindex="${visibleColumnIndex}"]`).focus(); - }); - } - if (expanded || (!expanded && isScrolledToBottom)) { - grid.verticalScrollContainer.getVerticalScroll().dispatchEvent(new Event('scroll')); - if (shouldScroll) { - grid.parentVirtDir.getHorizontalScroll().dispatchEvent(new Event('scroll')); - } - } if (grid.rowEditable) { grid.endEdit(true); } + + requestAnimationFrame(() => { + const cellID = grid.selection.first_item(`${id}-cell`); + if (cellID) { + const cell = this.get_cell_by_index(id, cellID.rowIndex, cellID.columnID); + if (cell) { + cell.nativeElement.focus(); + } + } + }); } public get_row_expansion_state(id: string, rowID: any, indentationLevel: number): boolean {