From 64a7260a704f6d870befdc0779118a379434dd9d Mon Sep 17 00:00:00 2001 From: Georgi Anastasov Date: Mon, 4 Nov 2024 09:56:38 +0200 Subject: [PATCH 1/2] feat(grid-summary): summary disabling with disabledSummaries property --- CHANGELOG.md | 5 + .../src/lib/grids/columns/column.component.ts | 31 ++++++ .../src/lib/grids/common/grid.interface.ts | 1 + .../src/lib/grids/grid/grid-summary.spec.ts | 98 +++++++++++++++++++ .../grids/summaries/grid-summary.service.ts | 39 +++++++- 5 files changed, 172 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fa934e1b721..ec0f7e77ed7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,11 @@ All notable changes for each version of this project will be documented in this file. +## 19.0.0 +### New Features +- `IgxColumn` + - Introduced the `disabledSummaries` property, allowing users to specify which summaries should be disabled for a given column. This property accepts an array of strings corresponding to the summary keys, enabling selective control over both default summaries (e.g., 'Count', 'Min') and any custom summaries created by the user. + ## 18.2.0 ### General - `IFilteringExpressionsTree`, `FilteringExpressionsTree` diff --git a/projects/igniteui-angular/src/lib/grids/columns/column.component.ts b/projects/igniteui-angular/src/lib/grids/columns/column.component.ts index f5da1e3002c..b4eb41bd8c4 100644 --- a/projects/igniteui-angular/src/lib/grids/columns/column.component.ts +++ b/projects/igniteui-angular/src/lib/grids/columns/column.component.ts @@ -1077,6 +1077,33 @@ export class IgxColumnComponent implements AfterContentInit, OnDestroy, ColumnTy this.grid.summaryService.resetSummaryHeight(); } } + + /** + * Sets/gets the summary operands to exclude from display. + * Accepts an array of string keys representing the summary types to disable, such as 'Min', 'Max', 'Count' etc. + * ```typescript + * let disabledSummaries = this.column.disabledSummaries; + * ``` + * ```html + * + * ``` + * + * @memberof IgxColumnComponent + */ + @Input() + public get disabledSummaries(): string[] { + return this._disabledSummaries; + } + + public set disabledSummaries(value: string[]) { + this._disabledSummaries = value; + if (this.grid) { + this.grid.summaryService.removeSummariesCachePerColumn(this.field); + this.grid.summaryPipeTrigger++; + this.grid.summaryService.resetSummaryHeight(); + } + } + /** * Gets the column `filters`. * ```typescript @@ -1743,6 +1770,10 @@ export class IgxColumnComponent implements AfterContentInit, OnDestroy, ColumnTy * @hidden */ protected _summaries = null; + /** + * @hidden + */ + private _disabledSummaries: string[] = []; /** * @hidden */ diff --git a/projects/igniteui-angular/src/lib/grids/common/grid.interface.ts b/projects/igniteui-angular/src/lib/grids/common/grid.interface.ts index 5e75b8754ec..767f042ce9f 100644 --- a/projects/igniteui-angular/src/lib/grids/common/grid.interface.ts +++ b/projects/igniteui-angular/src/lib/grids/common/grid.interface.ts @@ -443,6 +443,7 @@ export interface ColumnType extends FieldType { filteringExpressionsTree: FilteringExpressionsTree; hasSummary: boolean; summaries: any; + disabledSummaries?: string[]; /** * The template reference for a summary of the column * It is of type TemplateRef, which represents an embedded template, used to instantiate embedded views 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 bc04e7541b0..5ca311709de 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 @@ -134,6 +134,77 @@ describe('IgxGrid - Summaries #grid', () => { fixture.detectChanges(); }).not.toThrow(); }); + + it('should not display initially disabled summaries in the summary output', fakeAsync(() => { + grid.enableSummaries([{ fieldName: 'UnitsInStock' }]); + fixture.detectChanges(); + tick(); + + const column = grid.getColumnByName('UnitsInStock'); + + column.disabledSummaries = ['count', 'min', 'max']; + fixture.detectChanges(); + tick(); + + GridSummaryFunctions.verifyColumnSummaries( + GridSummaryFunctions.getRootSummaryRow(fixture), 3, + ['Sum', 'Avg'], + ['39,004', '3,900.4'] + ); + })); + + it('should apply disabled summaries dynamically at runtime', fakeAsync(() => { + grid.enableSummaries([{ fieldName: 'UnitsInStock' }]); + fixture.detectChanges(); + tick(); + + const column = grid.getColumnByName('UnitsInStock'); + + column.disabledSummaries = []; + fixture.detectChanges(); + tick(); + GridSummaryFunctions.verifyColumnSummaries( + GridSummaryFunctions.getRootSummaryRow(fixture), 3, + ['Count', 'Min', 'Max', 'Sum', 'Avg'], + ['10', '0', '20,000', '39,004', '3,900.4'] + ); + + column.disabledSummaries = ['count']; + fixture.detectChanges(); + tick(); + GridSummaryFunctions.verifyColumnSummaries( + GridSummaryFunctions.getRootSummaryRow(fixture), 3, + ['Min', 'Max', 'Sum', 'Avg'], + ['0', '20,000', '39,004', '3,900.4'] + ); + + column.disabledSummaries = ['count', 'sum']; + fixture.detectChanges(); + tick(); + GridSummaryFunctions.verifyColumnSummaries( + GridSummaryFunctions.getRootSummaryRow(fixture), 3, + ['Min', 'Max', 'Avg'], + ['0', '20,000', '3,900.4'] + ); + + column.disabledSummaries = ['count', 'sum', 'average']; + fixture.detectChanges(); + tick(); + GridSummaryFunctions.verifyColumnSummaries( + GridSummaryFunctions.getRootSummaryRow(fixture), 3, + ['Min', 'Max'], + ['0', '20,000'] + ); + + column.disabledSummaries = ['min', 'max']; + fixture.detectChanges(); + tick(); + GridSummaryFunctions.verifyColumnSummaries( + GridSummaryFunctions.getRootSummaryRow(fixture), 3, + ['Count', 'Sum', 'Avg'], + ['10', '39,004', '3,900.4'] + ); + })); }); describe('custom summaries: ', () => { @@ -238,6 +309,33 @@ describe('IgxGrid - Summaries #grid', () => { expect(lastColumnSummaryCellRect.right).toBe(lastColumnNormalCellRect.right, 'summary cell and data cell are not right aligned'); }); + + it('should apply disabledSummaries with custom summary', fakeAsync(() => { + grid.enableSummaries([{ fieldName: 'UnitsInStock' }]); + fixture.detectChanges(); + tick(); + + const column = grid.getColumnByName('UnitsInStock'); + column.summaries = fixture.componentInstance.inStockSummary; + fixture.detectChanges(); + tick(); + + GridSummaryFunctions.verifyColumnSummaries( + GridSummaryFunctions.getRootSummaryRow(fixture), 3, + ['Count', 'Min', 'Max', 'Sum', 'Avg', 'Items InStock'], + ['10', '0', '20,000', '39,004', '3,900.4', '6'] + ); + + column.disabledSummaries = ['test']; + fixture.detectChanges(); + tick(); + + GridSummaryFunctions.verifyColumnSummaries( + GridSummaryFunctions.getRootSummaryRow(fixture), 3, + ['Count', 'Min', 'Max', 'Sum', 'Avg'], + ['10', '0', '20,000', '39,004', '3,900.4'] + ); + })); }); describe('specific data: ', () => { 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 fa3dad5d6ee..0133621d210 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 @@ -116,16 +116,38 @@ export class IgxGridSummaryService { rowSummaries = new Map(); this.summaryCacheMap.set(rowID, rowSummaries); } + if (!this.hasSummarizedColumns || !data) { return rowSummaries; } + this.grid.columns.filter(col => col.hasSummary).forEach((column) => { if (!rowSummaries.get(column.field)) { - const summaryResult = column.summaries.operate(data.map(r => resolveNestedPath(r, column.field)), - data, column.field, groupRecord, this.grid.locale, column.pipeArgs); + let summaryResult = column.disabledSummaries.length + ? this.getCachedSummary(column.field, column.disabledSummaries) || null + : null; + + if (!summaryResult) { + summaryResult = column.summaries.operate( + data.map(r => resolveNestedPath(r, column.field)), + data, + column.field, + groupRecord, + this.grid.locale, + column.pipeArgs + ); + + if (column.disabledSummaries.length) { + summaryResult = summaryResult.filter( + result => !column.disabledSummaries.includes(result.key) + ); + this.cacheSummary(column.field, summaryResult, column.disabledSummaries); + } + } rowSummaries.set(column.field, summaryResult); } }); + return rowSummaries; } @@ -244,4 +266,17 @@ export class IgxGridSummaryService { }); } } + + private cacheSummary(field: string, summaryResult: IgxSummaryResult[], disabledSummaries: string[] = []) { + if (!this.summaryCacheMap.has(field)) { + this.summaryCacheMap.set(field, new Map()); + } + const cacheKey = JSON.stringify(disabledSummaries); + this.summaryCacheMap.get(field).set(cacheKey, summaryResult); + } + + private getCachedSummary(field: string, disabledSummaries: string[] = []): IgxSummaryResult[] | undefined { + const cacheKey = JSON.stringify(disabledSummaries); + return this.summaryCacheMap.get(field)?.get(cacheKey); + } } From 5ea07dcf0354922372cdf4a06284cda7261d5261 Mon Sep 17 00:00:00 2001 From: Georgi Anastasov Date: Tue, 12 Nov 2024 11:33:49 +0200 Subject: [PATCH 2/2] feat(summary): refactor summary calculation to simplify and improve row height --- .../grids/summaries/grid-summary.service.ts | 59 +++++++------------ 1 file changed, 20 insertions(+), 39 deletions(-) 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 0133621d210..2f3977d53ec 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 @@ -10,7 +10,7 @@ export class IgxGridSummaryService { public grid: GridType; public rootSummaryID = 'igxGridRootSummary'; public summaryHeight = 0; - public maxSummariesLenght = 0; + public maxSummariesLength = 0; public groupingExpressions = []; public retriggerRootPipe = 0; public deleteOperation = false; @@ -98,14 +98,16 @@ export class IgxGridSummaryService { } let maxSummaryLength = 0; this.grid.columns.filter((col) => col.hasSummary && !col.hidden).forEach((column) => { - const getCurrentSummaryColumn = column.summaries.operate([], [], column.field).length; - if (getCurrentSummaryColumn) { - if (maxSummaryLength < getCurrentSummaryColumn) { - maxSummaryLength = getCurrentSummaryColumn; - } + const getCurrentSummary = column.summaries.operate([], [], column.field); + const getCurrentSummaryColumn = column.disabledSummaries.length > 0 + ? getCurrentSummary.filter(s => !column.disabledSummaries.includes(s.key)).length + : getCurrentSummary.length; + + if (maxSummaryLength < getCurrentSummaryColumn) { + maxSummaryLength = getCurrentSummaryColumn; } }); - this.maxSummariesLenght = maxSummaryLength; + this.maxSummariesLength = maxSummaryLength; this.summaryHeight = maxSummaryLength * this.grid.defaultSummaryHeight; return this.summaryHeight; } @@ -123,27 +125,19 @@ export class IgxGridSummaryService { this.grid.columns.filter(col => col.hasSummary).forEach((column) => { if (!rowSummaries.get(column.field)) { - let summaryResult = column.disabledSummaries.length - ? this.getCachedSummary(column.field, column.disabledSummaries) || null - : null; + let summaryResult = column.summaries.operate( + data.map(r => resolveNestedPath(r, column.field)), + data, + column.field, + groupRecord, + this.grid.locale, + column.pipeArgs + ); - if (!summaryResult) { - summaryResult = column.summaries.operate( - data.map(r => resolveNestedPath(r, column.field)), - data, - column.field, - groupRecord, - this.grid.locale, - column.pipeArgs - ); + summaryResult = column.disabledSummaries.length > 0 + ? summaryResult.filter(s => !column.disabledSummaries.includes(s.key)) + : summaryResult; - if (column.disabledSummaries.length) { - summaryResult = summaryResult.filter( - result => !column.disabledSummaries.includes(result.key) - ); - this.cacheSummary(column.field, summaryResult, column.disabledSummaries); - } - } rowSummaries.set(column.field, summaryResult); } }); @@ -266,17 +260,4 @@ export class IgxGridSummaryService { }); } } - - private cacheSummary(field: string, summaryResult: IgxSummaryResult[], disabledSummaries: string[] = []) { - if (!this.summaryCacheMap.has(field)) { - this.summaryCacheMap.set(field, new Map()); - } - const cacheKey = JSON.stringify(disabledSummaries); - this.summaryCacheMap.get(field).set(cacheKey, summaryResult); - } - - private getCachedSummary(field: string, disabledSummaries: string[] = []): IgxSummaryResult[] | undefined { - const cacheKey = JSON.stringify(disabledSummaries); - return this.summaryCacheMap.get(field)?.get(cacheKey); - } }