Skip to content

Commit

Permalink
feat(groupby): adding grouping strategy option #10223
Browse files Browse the repository at this point in the history
  • Loading branch information
ChronosSF committed Oct 21, 2021
1 parent 6cde02d commit 83ba670
Show file tree
Hide file tree
Showing 9 changed files with 119 additions and 36 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@

All notable changes for each version of this project will be documented in this file.

## 12.2.4

### General
- `igxGrid`
- Exposed a `groupStrategy` input that functions similarly to `sortStrategy`, allowing customization of the grouping behavior of the grid. Please, refer to the [Group By ](https://www.infragistics.com/products/ignite-ui-angular/angular/components/grid/groupby) topic for more information.

## 12.2.1

### New Features
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ const testGroupBy = () => {
// sort
const res = DataUtil.sort(data, [expr]);
// group by
DataUtil.group(res, state, null, groupRecords);
DataUtil.group(res, state, null, null, groupRecords);
expect(groupRecords.length).toEqual(2);
expect(groupRecords[0].records.length).toEqual(3);
expect(groupRecords[1].records.length).toEqual(2);
Expand All @@ -279,7 +279,7 @@ const testGroupBy = () => {
// sort
const sorted = DataUtil.sort(data, [expr, expr2]);
// group by
DataUtil.group(sorted, state, null, groupRecords);
DataUtil.group(sorted, state, null, null, groupRecords);
expect(groupRecords.length).toEqual(2);
expect(groupRecords[0].records.length).toEqual(3);
expect(groupRecords[1].records.length).toEqual(2);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { IGroupByRecord } from './groupby-record.interface';
import { IGroupingState } from './groupby-state.interface';
import { ISortingExpression } from './sorting-expression.interface';
import { FilteringStrategy } from './filtering-strategy';
import { IGridGroupingStrategy } from './grouping-strategy';
import { ITreeGridRecord } from '../grids/tree-grid/public_api';
import { cloneValue, mergeObjects, mkenum } from '../core/utils';
import { Transaction, TransactionType, HierarchicalTransaction } from '../services/transaction/transaction';
Expand Down Expand Up @@ -73,9 +74,8 @@ export class DataUtil {
return rec;
}

public static group<T>(data: T[], state: IGroupingState, grid: GridType = null,
public static group<T>(data: T[], state: IGroupingState, grouping: IGridGroupingStrategy = new IgxGrouping(), grid: GridType = null,
groupsRecords: any[] = [], fullResult: IGroupByResult = { data: [], metadata: [] }): IGroupByResult {
const grouping = new IgxGrouping();
groupsRecords.splice(0, groupsRecords.length);
return grouping.groupBy(data, state, grid, groupsRecords, fullResult);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
import { IGroupByRecord } from './groupby-record.interface';
import { IgxSorting } from './sorting-strategy';
import { IgxSorting, IGridSortingStrategy } from './sorting-strategy';
import { IGroupingState } from './groupby-state.interface';
import { IGroupByResult } from './grouping-result.interface';

export class IgxGrouping extends IgxSorting {

export interface IGridGroupingStrategy extends IGridSortingStrategy {
groupBy(data: any[], state: IGroupingState, grid?: any, groupsRecords?: any[], fullResult?: IGroupByResult): IGroupByResult;
}

export class IgxGrouping extends IgxSorting implements IGridGroupingStrategy {
public groupBy(data: any[], state: IGroupingState, grid?: any,
groupsRecords?: any[], fullResult: IGroupByResult = { data: [], metadata: [] }): IGroupByResult {
const metadata: IGroupByRecord[] = [];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@
| visibleColumns:hasVisibleColumns
| gridFiltering:filteringExpressionsTree:filterStrategy:advancedFilteringExpressionsTree:id:pipeTrigger:filteringPipeTrigger
| gridSort:sortingExpressions:sortStrategy:id:pipeTrigger
| gridGroupBy:groupingExpressions:groupingExpansionState:groupsExpanded:id:groupsRecords:pipeTrigger
| gridGroupBy:groupingExpressions:groupingExpansionState:groupStrategy:groupsExpanded:id:groupsRecords:pipeTrigger
| gridPaging:paginator?.page:paginator?.perPage:id:pipeTrigger
| gridSummary:hasSummarizedColumns:summaryCalculationMode:summaryPosition:id:showSummaryOnCollapse:pipeTrigger:summaryPipeTrigger
| gridDetails:hasDetails:expansionStates:pipeTrigger
Expand Down
24 changes: 24 additions & 0 deletions projects/igniteui-angular/src/lib/grids/grid/grid.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import { IgxGridGroupByAreaComponent } from '../grouping/grid-group-by-area.comp
import { IgxGridCell } from '../grid-public-cell';
import { CellType } from '../common/cell.interface';
import { DeprecateMethod } from '../../core/deprecateDecorators';
import { IGridGroupingStrategy } from '../../data-operations/grouping-strategy';

let NEXT_ID = 0;

Expand Down Expand Up @@ -263,6 +264,10 @@ export class IgxGridComponent extends IgxGridBaseDirective implements GridType,
* @hidden
*/
protected _groupAreaTemplate: TemplateRef<any>;
/**
* @hidden
*/
protected _groupStrategy: IGridGroupingStrategy;
/**
* @hidden
*/
Expand Down Expand Up @@ -455,6 +460,25 @@ export class IgxGridComponent extends IgxGridBaseDirective implements GridType,
this._hideGroupedColumns = value;
}

/**
* Gets/Sets the grouping strategy of the grid.
*
* @remarks The default IgxGrouping extends from IgxSorting and a custom one can be used as a `sortStrategy` as well.
*
* @example
* ```html
* <igx-grid #grid [data]="localData" [groupStrategy]="groupStrategy"></igx-grid>
* ```
*/
@Input()
public get groupStrategy(): IGridGroupingStrategy {
return this._groupStrategy;
}

public set groupStrategy(value: IGridGroupingStrategy) {
this._groupStrategy = value;
}

/**
* Gets/Sets the message displayed inside the GroupBy drop area where columns can be dragged on.
*
Expand Down
98 changes: 72 additions & 26 deletions projects/igniteui-angular/src/lib/grids/grid/grid.groupby.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { GridSelectionFunctions, GridFunctions } from '../../test-utils/grid-fun
import { GridSelectionMode } from '../common/enums';
import { ControlsFunction } from '../../test-utils/controls-functions.spec';
import { IGroupingExpression } from '../../data-operations/grouping-expression.interface';
import { IgxGrouping } from '../../data-operations/grouping-strategy';

describe('IgxGrid - GroupBy #grid', () => {

Expand Down Expand Up @@ -602,6 +603,21 @@ describe('IgxGrid - GroupBy #grid', () => {
expect(grid.groupingExpressionsChange.emit).toHaveBeenCalledTimes(0);
}));

it('should group unbound column with custom grouping strategy', fakeAsync(() => {
const fix = TestBed.createComponent(GroupableGridComponent);
fix.componentInstance.data.forEach((r, i) => {
r['fieldValue1'] = Math.floor(i / 3);
r['fieldValue2'] = Math.floor(i / 4);
});
fix.detectChanges();
fix.componentInstance.instance.groupBy({
fieldName: 'UnboundField', dir: SortingDirection.Desc, ignoreCase: false
});
fix.detectChanges();
const groupRows = fix.componentInstance.instance.groupsRowList.toArray();
expect(groupRows.length).toEqual(4);
}));

// GroupBy + Sorting integration
it('should apply sorting on each group\'s records when non-grouped column is sorted.', fakeAsync(() => {
const fix = TestBed.createComponent(DefaultGridComponent);
Expand Down Expand Up @@ -1848,36 +1864,36 @@ describe('IgxGrid - GroupBy #grid', () => {
}));

it('Should have the correct properties in the custom row selector template', fakeAsync(() => {
const fix = TestBed.createComponent(GridGroupByRowCustomSelectorsComponent);
const grid = fix.componentInstance.instance;
fix.componentInstance.width = '1200px';
tick();
grid.columnWidth = '200px';
tick();
grid.rowSelection = GridSelectionMode.multiple;
tick();
fix.detectChanges();
const fix = TestBed.createComponent(GridGroupByRowCustomSelectorsComponent);
const grid = fix.componentInstance.instance;
fix.componentInstance.width = '1200px';
tick();
grid.columnWidth = '200px';
tick();
grid.rowSelection = GridSelectionMode.multiple;
tick();
fix.detectChanges();

grid.groupBy({
fieldName: 'ProductName', dir: SortingDirection.Desc, ignoreCase: false
});
tick();
fix.detectChanges();
grid.groupBy({
fieldName: 'ProductName', dir: SortingDirection.Desc, ignoreCase: false
});
tick();
fix.detectChanges();

const grRow = grid.groupsRowList.toArray()[0];
const contextSelect = { selectedCount: 0, totalCount: 2, groupRow: grid.groupsRowList.toArray()[0].groupRow };
const contextUnselect = { selectedCount: 2, totalCount: 2, groupRow: grid.groupsRowList.toArray()[0].groupRow };
const grRow = grid.groupsRowList.toArray()[0];
const contextSelect = { selectedCount: 0, totalCount: 2, groupRow: grid.groupsRowList.toArray()[0].groupRow };
const contextUnselect = { selectedCount: 2, totalCount: 2, groupRow: grid.groupsRowList.toArray()[0].groupRow };

spyOn(fix.componentInstance, 'onGroupByRowClick').and.callThrough();
spyOn(fix.componentInstance, 'onGroupByRowClick').and.callThrough();

grRow.nativeElement.querySelector('.igx-checkbox__composite').click();
fix.detectChanges();
expect(fix.componentInstance.onGroupByRowClick).toHaveBeenCalledWith(fix.componentInstance.groupByRowClick, contextSelect);
grRow.nativeElement.querySelector('.igx-checkbox__composite').click();
fix.detectChanges();
expect(fix.componentInstance.onGroupByRowClick).toHaveBeenCalledWith(fix.componentInstance.groupByRowClick, contextSelect);

grRow.nativeElement.querySelector('.igx-checkbox__composite').click();
fix.detectChanges();
expect(fix.componentInstance.onGroupByRowClick).toHaveBeenCalledWith(fix.componentInstance.groupByRowClick, contextUnselect);
}));
grRow.nativeElement.querySelector('.igx-checkbox__composite').click();
fix.detectChanges();
expect(fix.componentInstance.onGroupByRowClick).toHaveBeenCalledWith(fix.componentInstance.groupByRowClick, contextUnselect);
}));

// GroupBy + Resizing
it('should retain same size for group row after a column is resized.', fakeAsync(() => {
Expand Down Expand Up @@ -3488,19 +3504,42 @@ export class DefaultGridComponent extends DataParent {
}
}

const formatUnboundValueFunction = (rowData: any | undefined): string | undefined => rowData.fieldValue1 + ' ' + rowData.fieldValue2;


class MySortingStrategy extends IgxGrouping {
protected getFieldValue(
obj: any,
key: string,
isDate = false,
isTime = false
): unknown {
if (key !== 'UnboundField') {
return super.getFieldValue(obj, key, isDate, isTime);
}

return formatUnboundValueFunction(obj);
}
}

@Component({
template: `
<igx-grid
[width]='width'
[height]='height'
[data]="data">
[data]="data"
[sortStrategy]="sortStrategy"
[groupStrategy]="groupStrategy">
<igx-column [field]="'ID'" [header]="'ID'" [width]="200" [groupable]="true" [hasSummary]="false"></igx-column>
<igx-column [field]="'ReleaseDate'" [header]="'ReleaseDate'" [width]="200" [groupable]="true" [hasSummary]="false"
dataType="date"></igx-column>
<igx-column [field]="'Downloads'" [header]="'Downloads'" [width]="200" [groupable]="true" [hasSummary]="false"
dataType="number"></igx-column>
<igx-column [field]="'ProductName'" [header]="'ProductName'" [width]="200" [groupable]="true" [hasSummary]="false"></igx-column>
<igx-column [field]="'Released'" [header]="'Released'" [width]="200" [groupable]="true" [hasSummary]="false"></igx-column>
<igx-column [field]="'UnboundField'" [header]="'Unbound Value'" [width]="200" [dataType]="'string'"
[sortable]="true" [groupable]="true" [formatter]="formatUnboundValue">
</igx-column>
<igx-paginator></igx-paginator>
</igx-grid>
`
Expand All @@ -3511,6 +3550,13 @@ export class GroupableGridComponent extends DataParent {

public width = '800px';
public height = '700px';

public sortStrategy = new MySortingStrategy();
public groupStrategy = this.sortStrategy;

public formatUnboundValue(value: string, rowData: any | undefined): string | undefined {
return formatUnboundValueFunction(rowData);
}
}

@Component({
Expand Down
6 changes: 4 additions & 2 deletions projects/igniteui-angular/src/lib/grids/grid/grid.pipes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { IgxGridBaseDirective } from '../grid-base.directive';
import { GridType } from '../common/grid.interface';
import { IFilteringStrategy } from '../../data-operations/filtering-strategy';
import { IGridSortingStrategy } from '../../data-operations/sorting-strategy';
import { IGridGroupingStrategy } from '../../data-operations/grouping-strategy';
import { GridPagingMode } from '../common/enums';

/**
Expand Down Expand Up @@ -60,7 +61,8 @@ export class IgxGridGroupingPipe implements PipeTransform {
}

public transform(collection: any[], expression: IGroupingExpression | IGroupingExpression[],
expansion: IGroupByExpandState | IGroupByExpandState[], defaultExpanded: boolean,
expansion: IGroupByExpandState | IGroupByExpandState[],
groupingStrategy: IGridGroupingStrategy, defaultExpanded: boolean,
id: string, groupsRecords: any[], _pipeTrigger: number): IGroupByResult {

const state = { expressions: [], expansion: [], defaultExpanded };
Expand All @@ -79,7 +81,7 @@ export class IgxGridGroupingPipe implements PipeTransform {
} else {
state.expansion = grid.groupingExpansionState;
state.defaultExpanded = grid.groupsExpanded;
result = DataUtil.group(cloneArray(collection), state, grid, groupsRecords, fullResult);
result = DataUtil.group(cloneArray(collection), state, groupingStrategy, grid, groupsRecords, fullResult);
}
grid.groupingFlatResult = result.data;
grid.groupingResult = fullResult.data;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -694,7 +694,7 @@ export abstract class IgxBaseExporter {

if (hasGrouping && !this.options.ignoreGrouping) {
const groupsRecords = [];
DataUtil.group(cloneArray(gridData), groupedGridGroupingState, grid, groupsRecords);
DataUtil.group(cloneArray(gridData), groupedGridGroupingState, grid.groupStrategy, grid, groupsRecords);
gridData = groupsRecords;
}

Expand Down

0 comments on commit 83ba670

Please sign in to comment.