Skip to content

Commit 83e9fb8

Browse files
Merge pull request #6086 from IgniteUI/tzhelev/noop-strategies
Expose NoopFilterStrategy and NoopSortStrategy for the grids
2 parents 8b3fac7 + 60f3b19 commit 83e9fb8

13 files changed

+152
-17
lines changed

CHANGELOG.md

+7
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,13 @@ All notable changes for each version of this project will be documented in this
1717
- **Behavioral Change** - Pinning columns is no longer automatically prevented when the pinning area would exceed the size of the grid.
1818

1919
### New Features
20+
- `IgxGrid`, `IgxTreeGrid`, `IgxHierarchicalGrid`:
21+
- `sortStrategy` input is added, which can be used to set a global sorting strategy for the entire grid.
22+
(**NOTE**: The grid's `sortStrategy` is of different type compared to the column's `sortStrategy`.)
23+
- `NoopSortingStrategy` is added, which can be used to disable the default sorting of the grid by assigning its instance to the grid's `sortStrategy` input. (Useful for remote sorting.)
24+
- `NoopFilteringStrategy` is added, which can be used to disable the default filtering of the grid by assigning its instance to the grid's `filterStrategy` input. (Useful for remote filtering.)
25+
- `sortingExpressionsChange` event emitter is added, which is fired whenever a change to the sorting expressions has occurred (prior to performing the actual sorting).
26+
- `filteringExpressionsTreeChange` event emitter is added, which is fired whenever a change to the filtering expressions has occurred (prior to performing the actual filtering).
2027
- `IgxOverlayService`:
2128
- `setOffset` method added. It offsets the content along the corresponding axis by the provided amount.
2229
- `IgxToggleDirective`:

projects/igniteui-angular/src/lib/data-operations/data-util.ts

+5-4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { IFilteringState } from './filtering-state.interface';
22

3-
import { IgxSorting, IgxDataRecordSorting } from './sorting-strategy';
3+
import { IgxSorting, IgxDataRecordSorting, IGridSortingStrategy } from './sorting-strategy';
44
import { IgxGrouping } from './grouping-strategy';
55
import { IGroupByResult } from './grouping-result.interface';
66

@@ -30,24 +30,25 @@ export enum DataType {
3030
* @hidden
3131
*/
3232
export class DataUtil {
33-
public static sort<T>(data: T[], expressions: ISortingExpression[], sorting: IgxSorting = new IgxSorting()): T[] {
33+
public static sort<T>(data: T[], expressions: ISortingExpression[], sorting: IGridSortingStrategy = new IgxSorting()): T[] {
3434
return sorting.sort(data, expressions);
3535
}
3636

3737
public static treeGridSort(hierarchicalData: ITreeGridRecord[],
3838
expressions: ISortingExpression[],
39+
sorting: IGridSortingStrategy = new IgxDataRecordSorting(),
3940
parent?: ITreeGridRecord): ITreeGridRecord[] {
4041
let res: ITreeGridRecord[] = [];
4142
hierarchicalData.forEach((hr: ITreeGridRecord) => {
4243
const rec: ITreeGridRecord = DataUtil.cloneTreeGridRecord(hr);
4344
rec.parent = parent;
4445
if (rec.children) {
45-
rec.children = DataUtil.treeGridSort(rec.children, expressions, rec);
46+
rec.children = DataUtil.treeGridSort(rec.children, expressions, sorting, rec);
4647
}
4748
res.push(rec);
4849
});
4950

50-
res = DataUtil.sort(res, expressions, new IgxDataRecordSorting());
51+
res = DataUtil.sort(res, expressions, sorting);
5152

5253
return res;
5354
}

projects/igniteui-angular/src/lib/data-operations/filtering-strategy.ts

+14
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,20 @@ export interface IFilteringStrategy {
55
filter(data: any[], expressionsTree: IFilteringExpressionsTree, advancedExpressionsTree?: IFilteringExpressionsTree): any[];
66
}
77

8+
export class NoopFilteringStrategy implements IFilteringStrategy {
9+
private static _instance: NoopFilteringStrategy = null;
10+
11+
private constructor() { }
12+
13+
public static instance() {
14+
return this._instance || (this._instance = new NoopFilteringStrategy());
15+
}
16+
17+
public filter(data: any[], expressionsTree: IFilteringExpressionsTree, advancedExpressionsTree?: IFilteringExpressionsTree): any[] {
18+
return data;
19+
}
20+
}
21+
822
export abstract class BaseFilteringStrategy implements IFilteringStrategy {
923
public abstract filter(data: any[], expressionsTree: IFilteringExpressionsTree,
1024
advancedExpressionsTree?: IFilteringExpressionsTree): any[];

projects/igniteui-angular/src/lib/data-operations/sorting-strategy.ts

+19-1
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,25 @@ export class DefaultSortingStrategy implements ISortingStrategy {
7171
}
7272
}
7373

74-
export class IgxSorting {
74+
export interface IGridSortingStrategy {
75+
sort(data: any[], expressions: ISortingExpression[]): any[];
76+
}
77+
78+
export class NoopSortingStrategy implements IGridSortingStrategy {
79+
private static _instance: NoopSortingStrategy = null;
80+
81+
private constructor() { }
82+
83+
public static instance() {
84+
return this._instance || (this._instance = new NoopSortingStrategy());
85+
}
86+
87+
public sort(data: any[], expressions: ISortingExpression[]): any[] {
88+
return data;
89+
}
90+
}
91+
92+
export class IgxSorting implements IGridSortingStrategy {
7593
public sort(data: any[], expressions: ISortingExpression[]): any[] {
7694
return this.sortDataRecursive(data, expressions);
7795
}

projects/igniteui-angular/src/lib/grids/grid-base.directive.ts

+45-2
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ import { IgxHeadSelectorDirective, IgxRowSelectorDirective } from './selection/r
131131
import { IgxGridToolbarCustomContentDirective } from './toolbar/toolbar.directive';
132132
import { IgxColumnComponent } from './columns/column.component';
133133
import { IgxColumnGroupComponent } from './columns/column-group.component';
134+
import { IGridSortingStrategy } from '../data-operations/sorting-strategy';
134135

135136
const MINIMUM_COLUMN_WIDTH = 136;
136137
const FILTER_ROW_HEIGHT = 50;
@@ -168,6 +169,7 @@ export class IgxGridBaseDirective extends DisplayDensityBase implements
168169
public _destroyed = false;
169170
private overlayIDs = [];
170171
private _filteringStrategy: IFilteringStrategy;
172+
private _sortingStrategy: IGridSortingStrategy;
171173

172174
private _hostWidth;
173175
private _advancedFilteringOverlayId: string;
@@ -327,7 +329,18 @@ export class IgxGridBaseDirective extends DisplayDensityBase implements
327329
}
328330

329331
/**
330-
*@hidden
332+
* Emitted before filtering is performed.
333+
* Returns the filtering expressions tree of the column for which filtering was performed.
334+
* ```typescript
335+
* filteringExprTreeChange(event: IFilteringExpressionsTree){
336+
* const filteringTree = event;
337+
* }
338+
* ```
339+
* ```html
340+
* <igx-grid #grid [data]="localData" [height]="'305px'" [autoGenerate]="true"
341+
* (filteringExpressionsTreeChange)="filteringExprTreeChange($event)"></igx-grid>
342+
* ```
343+
* @memberof IgxGridBaseDirective
331344
*/
332345
@Output()
333346
public filteringExpressionsTreeChange = new EventEmitter<IFilteringExpressionsTree>();
@@ -1078,6 +1091,27 @@ export class IgxGridBaseDirective extends DisplayDensityBase implements
10781091
this._filteringStrategy = classRef;
10791092
}
10801093

1094+
/**
1095+
* Gets the sorting strategy of the grid.
1096+
* ```typescript
1097+
* let sortStrategy = this.grid.sortStrategy
1098+
* ```
1099+
*/
1100+
@Input()
1101+
get sortStrategy(): IGridSortingStrategy {
1102+
return this._sortingStrategy;
1103+
}
1104+
1105+
/**
1106+
* Sets the sorting strategy of the grid.
1107+
* ```html
1108+
* <igx-grid #grid [data]="localData" [sortStrategy]="sortStrategy"></igx-grid>
1109+
* ```
1110+
*/
1111+
set sortStrategy(value: IGridSortingStrategy) {
1112+
this._sortingStrategy = value;
1113+
}
1114+
10811115
/**
10821116
* An @Input property that provides a callback for loading unique column values on demand.
10831117
* If this property is provided, the unique values it generates will be used by the Excel Style Filtering.
@@ -2155,7 +2189,16 @@ export class IgxGridBaseDirective extends DisplayDensityBase implements
21552189
}
21562190

21572191
/**
2158-
*@hidden
2192+
* Emitted before sorting is performed. Returns the sorting expressions.
2193+
* ```html
2194+
* <igx-grid #grid [data]="localData" [autoGenerate]="true" (sortingExpressionsChange)="sortingExprChange($event)"></igx-grid>
2195+
* ```
2196+
* ```typescript
2197+
* sortingExprChange(event: ISortingExpression[]){
2198+
* const sortingExpressions = event;
2199+
* }
2200+
* ```
2201+
* @memberof IgxGridBaseDirective
21592202
*/
21602203
@Output()
21612204
public sortingExpressionsChange = new EventEmitter<ISortingExpression[]>();

projects/igniteui-angular/src/lib/grids/grid/grid-filtering-ui.spec.ts

+21
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ import {
4545
} from '../../test-utils/grid-samples.spec';
4646
import { HelperUtils } from '../../test-utils/helper-utils.spec';
4747
import { GridSelectionMode, FilterMode } from '../common/enums';
48+
import { NoopFilteringStrategy } from '../../data-operations/filtering-strategy';
4849

4950
const FILTER_UI_ROW = 'igx-grid-filtering-row';
5051
const FILTER_UI_CELL = 'igx-grid-filtering-cell';
@@ -3422,6 +3423,26 @@ describe('IgxGrid - Filtering Row UI actions #grid', () => {
34223423
expect(chip.componentInstance.selected).toBeTruthy();
34233424
}));
34243425

3426+
it('Should disable filtering feature when using NoopFilteringStrategy.', (async () => {
3427+
// Use the NoopFilteringStrategy.
3428+
grid.filterStrategy = NoopFilteringStrategy.instance();
3429+
fix.detectChanges();
3430+
3431+
GridFunctions.clickFilterCellChip(fix, 'ProductName');
3432+
fix.detectChanges();
3433+
3434+
// Add first chip.
3435+
GridFunctions.typeValueInFilterRowInput('some value', fix);
3436+
await wait(16);
3437+
GridFunctions.submitFilterRowInput(fix);
3438+
await wait(100);
3439+
3440+
// Verify the grid is not filtered, because of the noop filter strategy.
3441+
expect(grid.rowList.length).toBe(8);
3442+
expect(GridFunctions.getCurrentCellFromGrid(grid, 0, 1).value).toBe('Ignite UI for JavaScript');
3443+
expect(GridFunctions.getCurrentCellFromGrid(grid, 1, 1).value).toBe('NetAdvantage');
3444+
}));
3445+
34253446
it('Should close filterRow when changing filterMode from \'quickFilter\' to \'excelStyleFilter\'', (async () => {
34263447
GridFunctions.clickFilterCellChip(fix, 'ProductName');
34273448
fix.detectChanges();

projects/igniteui-angular/src/lib/grids/grid/grid.component.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@
107107
| gridTransaction:id:pipeTrigger
108108
| visibleColumns:hasVisibleColumns
109109
| gridFiltering:filteringExpressionsTree:filterStrategy:advancedFilteringExpressionsTree:id:pipeTrigger
110-
| gridSort:sortingExpressions:id:pipeTrigger
110+
| gridSort:sortingExpressions:sortStrategy:id:pipeTrigger
111111
| gridGroupBy:groupingExpressions:groupingExpansionState:groupsExpanded:id:groupsRecords:pipeTrigger
112112
| gridPaging:page:perPage:id:pipeTrigger
113113
| gridSummary:hasSummarizedColumns:summaryCalculationMode:summaryPosition:id:pipeTrigger:summaryPipeTrigger"

projects/igniteui-angular/src/lib/grids/grid/grid.pipes.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import { GridBaseAPIService } from '../api.service';
1212
import { IgxGridBaseDirective } from '../grid-base.directive';
1313
import { GridType } from '../common/grid.interface';
1414
import { IFilteringStrategy } from '../../data-operations/filtering-strategy';
15+
import { IGridSortingStrategy } from '../../data-operations/sorting-strategy';
1516

1617
/**
1718
*@hidden
@@ -27,14 +28,15 @@ export class IgxGridSortingPipe implements PipeTransform {
2728
this.gridAPI = <IgxGridAPIService>gridAPI;
2829
}
2930

30-
public transform(collection: any[], expressions: ISortingExpression[], id: string, pipeTrigger: number): any[] {
31+
public transform(collection: any[], expressions: ISortingExpression[], sorting: IGridSortingStrategy,
32+
id: string, pipeTrigger: number): any[] {
3133
const grid = this.gridAPI.grid;
3234
let result: any[];
3335

3436
if (!expressions.length) {
3537
result = collection;
3638
} else {
37-
result = DataUtil.sort(cloneArray(collection), expressions);
39+
result = DataUtil.sort(cloneArray(collection), expressions, sorting);
3840
}
3941
grid.filteredSortedData = result;
4042

projects/igniteui-angular/src/lib/grids/grid/grid.sorting.spec.ts

+27-1
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,13 @@ import { IgxGridModule } from './index';
77
import { GridTemplateStrings, ColumnDefinitions } from '../../test-utils/template-strings.spec';
88
import { BasicGridComponent } from '../../test-utils/grid-base-components.spec';
99
import { SampleTestData } from '../../test-utils/sample-test-data.spec';
10-
import { DefaultSortingStrategy, ISortingStrategy } from '../../data-operations/sorting-strategy';
10+
import { DefaultSortingStrategy, ISortingStrategy, NoopSortingStrategy } from '../../data-operations/sorting-strategy';
1111
import { IgxGridCellComponent } from '../cell.component';
1212
import { configureTestSuite } from '../../test-utils/configure-suite';
1313
import { IgxGridFilteringRowComponent } from '../filtering/base/grid-filtering-row.component';
1414
import { IgxChipComponent } from '../../chips/chip.component';
1515
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
16+
import { GridFunctions } from '../../test-utils/grid-functions.spec';
1617

1718
const SORTING_ICON_ASC_CONTENT = 'arrow_upward';
1819
const SORTING_ICON_DESC_CONTENT = 'arrow_downward';
@@ -353,6 +354,31 @@ describe('IgxGrid - Grid Sorting #grid', () => {
353354
expect(grid.headerGroups.toArray()[1].isFiltered).toBeTruthy();
354355
}));
355356

357+
it('Should disable sorting feature when using NoopSortingStrategy.', () => {
358+
grid.sortStrategy = NoopSortingStrategy.instance();
359+
fixture.detectChanges();
360+
361+
const gridData = fixture.componentInstance.data;
362+
const firstHeaderCell = GridFunctions.getColumnHeader('ID', fixture);
363+
364+
clickCurrentRow(firstHeaderCell);
365+
fixture.detectChanges();
366+
367+
// Verify that the grid is NOT sorted.
368+
expect(getValueFromCellElement(getCurrentCellFromGrid(grid, 0, 1))).toEqual('Jane');
369+
expect(getValueFromCellElement(getCurrentCellFromGrid(grid, grid.data.length - 1, 1))).toEqual('Connor');
370+
grid.rowList.map((item, index) =>
371+
expect(grid.getCellByColumn(index, 'ID').value).toEqual(gridData[index].ID));
372+
373+
clickCurrentRow(firstHeaderCell);
374+
fixture.detectChanges();
375+
376+
// Verify that the grid is NOT sorted.
377+
expect(getValueFromCellElement(getCurrentCellFromGrid(grid, 0, 1))).toEqual('Jane');
378+
expect(getValueFromCellElement(getCurrentCellFromGrid(grid, grid.data.length - 1, 1))).toEqual('Connor');
379+
grid.rowList.map((item, index) =>
380+
expect(grid.getCellByColumn(index, 'ID').value).toEqual(gridData[index].ID));
381+
});
356382

357383
it(`Should allow sorting using a custom Sorting Strategy.`, () => {
358384
fixture = TestBed.createComponent(SortByParityComponent);

projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.component.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@
8484
| gridTransaction:id:pipeTrigger
8585
| visibleColumns:hasVisibleColumns
8686
| gridFiltering:filteringExpressionsTree:filterStrategy:advancedFilteringExpressionsTree:id:pipeTrigger
87-
| gridSort:sortingExpressions:id:pipeTrigger
87+
| gridSort:sortingExpressions:sortStrategy:id:pipeTrigger
8888
| gridHierarchicalPaging:page:perPage:id:pipeTrigger
8989
| gridHierarchical:hierarchicalState:id:primaryKey:childLayoutKeys:pipeTrigger" let-rowIndex="index"
9090
[igxForScrollOrientation]="'vertical'" [igxForScrollContainer]='verticalScroll'

projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid.component.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@
7575
| visibleColumns:hasVisibleColumns
7676
| treeGridHierarchizing:primaryKey:foreignKey:childDataKey:id:pipeTrigger
7777
| treeGridFiltering:filteringExpressionsTree:filterStrategy:advancedFilteringExpressionsTree:id:pipeTrigger
78-
| treeGridSorting:sortingExpressions:id:pipeTrigger
78+
| treeGridSorting:sortingExpressions:sortStrategy:id:pipeTrigger
7979
| treeGridFlattening:id:expansionDepth:expansionStates:pipeTrigger
8080
| treeGridPaging:page:perPage:id:pipeTrigger
8181
| treeGridSummary:hasSummarizedColumns:summaryCalculationMode:summaryPosition:id:pipeTrigger:summaryPipeTrigger" let-rowIndex="index"

projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid.pipes.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { ITreeGridRecord } from './tree-grid.interfaces';
88
import { IgxGridBaseDirective } from '../grid';
99
import { ISortingExpression } from '../../data-operations/sorting-expression.interface';
1010
import { GridType } from '../common/grid.interface';
11+
import { IGridSortingStrategy } from '../../data-operations/sorting-strategy';
1112

1213
/**
1314
*@hidden
@@ -199,6 +200,7 @@ export class IgxTreeGridSortingPipe implements PipeTransform {
199200
public transform(
200201
hierarchicalData: ITreeGridRecord[],
201202
expressions: ISortingExpression[],
203+
sorting: IGridSortingStrategy,
202204
id: string,
203205
pipeTrigger: number): ITreeGridRecord[] {
204206
const grid = this.gridAPI.grid;
@@ -207,7 +209,7 @@ export class IgxTreeGridSortingPipe implements PipeTransform {
207209
if (!expressions.length) {
208210
result = hierarchicalData;
209211
} else {
210-
result = DataUtil.treeGridSort(hierarchicalData, expressions);
212+
result = DataUtil.treeGridSort(hierarchicalData, expressions, sorting);
211213
}
212214
const filteredSortedData = [];
213215
this.flattenTreeGridRecords(result, filteredSortedData);

projects/igniteui-angular/src/lib/services/exporter-common/base-export-service.ts

+4-3
Original file line numberDiff line numberDiff line change
@@ -266,12 +266,13 @@ export abstract class IgxBaseExporter {
266266

267267
if (this._isTreeGrid) {
268268
this.flatRecords = [];
269-
filteringState.strategy = new TreeGridFilteringStrategy();
269+
filteringState.strategy = (grid.filterStrategy) ? grid.filterStrategy : new TreeGridFilteringStrategy();
270270
rootRecords = filteringState.strategy.filter(rootRecords,
271271
filteringState.expressionsTree, filteringState.advancedExpressionsTree);
272272
this.prepareHierarchicalData(rootRecords);
273273
data = this.flatRecords;
274274
} else {
275+
filteringState.strategy = grid.filterStrategy;
275276
data = DataUtil.filter(data, filteringState);
276277
}
277278
}
@@ -283,11 +284,11 @@ export abstract class IgxBaseExporter {
283284

284285
if (this._isTreeGrid) {
285286
this.flatRecords = [];
286-
rootRecords = DataUtil.treeGridSort(rootRecords, grid.sortingExpressions);
287+
rootRecords = DataUtil.treeGridSort(rootRecords, grid.sortingExpressions, grid.sortStrategy);
287288
this.prepareHierarchicalData(rootRecords);
288289
data = this.flatRecords;
289290
} else {
290-
data = DataUtil.sort(data, grid.sortingExpressions);
291+
data = DataUtil.sort(data, grid.sortingExpressions, grid.sortStrategy);
291292
}
292293
}
293294

0 commit comments

Comments
 (0)