Skip to content

Commit a81fa9c

Browse files
MKirovaMKirova
authored andcommitted
Sort row dimension via chip.
1 parent 5759012 commit a81fa9c

File tree

9 files changed

+176
-70
lines changed

9 files changed

+176
-70
lines changed

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

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11

2+
import { parseDate } from '../core/utils';
3+
import { GridType } from '../grids/common/grid.interface';
24
import { IPivotDimension, IPivotKeys, IPivotValue, PivotDimensionType } from '../grids/pivot-grid/pivot-grid.interface';
35
import { PivotUtil } from '../grids/pivot-grid/pivot-util';
6+
import { GridColumnDataType } from './data-util';
7+
import { SortingDirection } from './sorting-expression.interface';
8+
import { DefaultSortingStrategy, ISortingStrategy } from './sorting-strategy';
49

510
export interface IPivotDimensionStrategy {
611
process(collection: any,
@@ -149,3 +154,40 @@ export class PivotColumnDimensionsStrategy implements IPivotDimensionStrategy {
149154
return !(record[pivotKeys.records] && record[pivotKeys.records].some(r => r[pivotKeys.records]));
150155
}
151156
}
157+
158+
export class DefaultPivotSortingStrategy extends DefaultSortingStrategy {
159+
protected static _instance: DefaultPivotSortingStrategy = null;
160+
protected dimension;
161+
public static instance(): DefaultPivotSortingStrategy {
162+
return this._instance || (this._instance = new this());
163+
}
164+
public sort(data: any[],
165+
fieldName: string,
166+
dir: SortingDirection,
167+
ignoreCase: boolean,
168+
valueResolver: (obj: any, key: string, isDate?: boolean) => any,
169+
isDate?: boolean,
170+
isTime?: boolean,
171+
grid?: GridType) {
172+
const key = fieldName;
173+
const config = (grid as any).pivotConfiguration;
174+
const allDimensions = config.rows.concat(config.columns).concat(config.filters).filter(x => x !== null);
175+
const enabledDimensions = allDimensions.filter(x => x && x.enabled);
176+
this.dimension = PivotUtil.flatten(enabledDimensions).find(x => x.memberName === key);
177+
const reverse = (dir === SortingDirection.Desc ? -1 : 1);
178+
const cmpFunc = (obj1, obj2) => this.compareObjects(obj1, obj2, key, reverse, ignoreCase, this.getFieldValue, isDate, isTime);
179+
return this.arraySort(data, cmpFunc);
180+
}
181+
182+
protected getFieldValue(obj: any, key: string, isDate: boolean = false, isTime: boolean = false): any {
183+
let resolvedValue = PivotUtil.extractValueFromDimension(this.dimension, obj);
184+
const formatAsDate = this.dimension.dataType === GridColumnDataType.Date || this.dimension.dataType === GridColumnDataType.DateTime;
185+
if (formatAsDate) {
186+
const date = parseDate(resolvedValue);
187+
resolvedValue = isTime && date ?
188+
new Date().setHours(date.getHours(), date.getMinutes(), date.getSeconds(), date.getMilliseconds()) : date;
189+
190+
}
191+
return resolvedValue;
192+
}
193+
}

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

Lines changed: 43 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,17 @@ const TIME_TYPE = 'time';
1313
const DATE_TIME_TYPE = 'dateTime';
1414
export interface ISortingStrategy {
1515
sort: (data: any[],
16-
fieldName: string,
17-
dir: SortingDirection,
18-
ignoreCase: boolean,
19-
valueResolver: (obj: any, key: string, isDate?: boolean) => any,
20-
isDate?: boolean,
21-
isTime?: boolean) => any[];
16+
fieldName: string,
17+
dir: SortingDirection,
18+
ignoreCase: boolean,
19+
valueResolver: (obj: any, key: string, isDate?: boolean) => any,
20+
isDate?: boolean,
21+
isTime?: boolean,
22+
grid?: GridType) => any[];
2223
}
2324

2425
export class DefaultSortingStrategy implements ISortingStrategy {
25-
private static _instance: DefaultSortingStrategy = null;
26+
protected static _instance: DefaultSortingStrategy = null;
2627

2728
protected constructor() {}
2829

@@ -31,12 +32,12 @@ export class DefaultSortingStrategy implements ISortingStrategy {
3132
}
3233

3334
public sort(data: any[],
34-
fieldName: string,
35-
dir: SortingDirection,
36-
ignoreCase: boolean,
37-
valueResolver: (obj: any, key: string, isDate?: boolean) => any,
38-
isDate?: boolean,
39-
isTime?: boolean) {
35+
fieldName: string,
36+
dir: SortingDirection,
37+
ignoreCase: boolean,
38+
valueResolver: (obj: any, key: string, isDate?: boolean) => any,
39+
isDate?: boolean,
40+
isTime?: boolean) {
4041
const key = fieldName;
4142
const reverse = (dir === SortingDirection.Desc ? -1 : 1);
4243
const cmpFunc = (obj1, obj2) => this.compareObjects(obj1, obj2, key, reverse, ignoreCase, valueResolver, isDate, isTime);
@@ -65,8 +66,8 @@ export class DefaultSortingStrategy implements ISortingStrategy {
6566
valueResolver: (obj: any, key: string, isDate?: boolean, isTime?: boolean) => any,
6667
isDate: boolean,
6768
isTime: boolean) {
68-
let a = valueResolver(obj1, key, isDate, isTime);
69-
let b = valueResolver(obj2, key, isDate, isTime);
69+
let a = valueResolver.call(this, obj1, key, isDate, isTime);
70+
let b = valueResolver.call(this, obj2, key, isDate, isTime);
7071
if (ignoreCase) {
7172
a = a && a.toLowerCase ? a.toLowerCase() : a;
7273
b = b && b.toLowerCase ? b.toLowerCase() : b;
@@ -163,38 +164,17 @@ export class IgxSorting implements IGridSortingStrategy {
163164
let resolvedValue = resolveNestedPath(obj, key);
164165
if (isDate || isTime) {
165166
const date = parseDate(resolvedValue);
166-
resolvedValue = isTime && date ?
167+
resolvedValue = isTime && date ?
167168
new Date().setHours(date.getHours(), date.getMinutes(), date.getSeconds(), date.getMilliseconds()) : date;
168169

169170
}
170171
return resolvedValue;
171172
}
172173

173-
private groupedRecordsByExpression(data: any[],
174-
index: number,
175-
expression: IGroupingExpression,
176-
isDate: boolean = false): any[] {
177-
const res = [];
178-
const key = expression.fieldName;
179-
const len = data.length;
180-
const groupval = this.getFieldValue(data[index], key, isDate);
181-
res.push(data[index]);
182-
index++;
183-
const comparer = expression.groupingComparer || DefaultSortingStrategy.instance().compareValues;
184-
for (let i = index; i < len; i++) {
185-
if (comparer(this.getFieldValue(data[i], key, isDate), groupval) === 0) {
186-
res.push(data[i]);
187-
} else {
188-
break;
189-
}
190-
}
191-
return res;
192-
}
193-
194-
private sortDataRecursive<T>(data: T[],
195-
expressions: ISortingExpression[],
196-
expressionIndex: number = 0,
197-
grid: GridType): T[] {
174+
protected sortDataRecursive<T>(data: T[],
175+
expressions: ISortingExpression[],
176+
expressionIndex: number = 0,
177+
grid: GridType): T[] {
198178
let i;
199179
let j;
200180
let gbData;
@@ -212,7 +192,7 @@ export class IgxSorting implements IGridSortingStrategy {
212192
const column = grid?.getColumnByName(expr.fieldName);
213193
const isDate = column?.dataType === DATE_TYPE || column?.dataType === DATE_TIME_TYPE;
214194
const isTime = column?.dataType === TIME_TYPE;
215-
data = expr.strategy.sort(data, expr.fieldName, expr.dir, expr.ignoreCase, this.getFieldValue, isDate, isTime);
195+
data = expr.strategy.sort(data, expr.fieldName, expr.dir, expr.ignoreCase, this.getFieldValue, isDate, isTime, grid);
216196
if (expressionIndex === exprsLen - 1) {
217197
return data;
218198
}
@@ -230,6 +210,27 @@ export class IgxSorting implements IGridSortingStrategy {
230210
}
231211
return data;
232212
}
213+
214+
private groupedRecordsByExpression(data: any[],
215+
index: number,
216+
expression: IGroupingExpression,
217+
isDate: boolean = false): any[] {
218+
const res = [];
219+
const key = expression.fieldName;
220+
const len = data.length;
221+
const groupval = this.getFieldValue(data[index], key, isDate);
222+
res.push(data[index]);
223+
index++;
224+
const comparer = expression.groupingComparer || DefaultSortingStrategy.instance().compareValues;
225+
for (let i = index; i < len; i++) {
226+
if (comparer(this.getFieldValue(data[i], key, isDate), groupval) === 0) {
227+
res.push(data[i]);
228+
} else {
229+
break;
230+
}
231+
}
232+
return res;
233+
}
233234
}
234235

235236
export class IgxDataRecordSorting extends IgxSorting {

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
class="igx-grid__scroll-on-drag-pinned" [style.left.px]="pinnedWidth"></span>
3333
<ng-template igxGridFor let-rowData [igxGridForOf]="data
3434
| pivotGridFilter:pivotConfiguration:filterStrategy:advancedFilteringExpressionsTree
35+
| pivotGridSort:pivotConfiguration:sortStrategy:id:pipeTrigger
3536
| pivotGridRow:pivotConfiguration:expansionStates:pipeTrigger
3637
| pivotGridRowExpansion:pivotConfiguration:expansionStates:pipeTrigger
3738
| pivotGridColumn:pivotConfiguration:expansionStates:pipeTrigger"

projects/igniteui-angular/src/lib/grids/pivot-grid/pivot-grid.interface.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { GridColumnDataType } from '../../data-operations/data-util';
22
import { FilteringExpressionsTree } from '../../data-operations/filtering-expressions-tree';
33
import { IPivotDimensionStrategy } from '../../data-operations/pivot-strategy';
4+
import { SortingDirection } from '../../data-operations/sorting-expression.interface';
45

56

67

@@ -27,6 +28,8 @@ export interface IPivotDimension {
2728
enabled: boolean;
2829
// A predefined or defined via the `igxPivotSelector` filter expression tree for the current dimension to be applied in the filter pipe.
2930
filter?: FilteringExpressionsTree | null;
31+
sortDirection?: SortingDirection;
32+
dataType?: GridColumnDataType;
3033
}
3134

3235
export interface IPivotValue {

projects/igniteui-angular/src/lib/grids/pivot-grid/pivot-grid.module.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
22
import { IgxGridModule } from '../grid/grid.module';
33
import { IgxPivotGridComponent } from './pivot-grid.component';
44
import { IgxPivotRowComponent } from './pivot-row.component';
5-
import { IgxPivotRowPipe, IgxPivotColumnPipe, IgxPivotGridFilterPipe, IgxPivotRowExpansionPipe } from './pivot-grid.pipes';
5+
import { IgxPivotRowPipe, IgxPivotColumnPipe, IgxPivotGridFilterPipe, IgxPivotRowExpansionPipe, IgxPivotGridSortingPipe } from './pivot-grid.pipes';
66
import { IgxGridComponent } from '../grid/grid.component';
77
import { IgxPivotHeaderRowComponent } from './pivot-header-row.component';
88

@@ -17,7 +17,8 @@ import { IgxPivotHeaderRowComponent } from './pivot-header-row.component';
1717
IgxPivotRowPipe,
1818
IgxPivotRowExpansionPipe,
1919
IgxPivotColumnPipe,
20-
IgxPivotGridFilterPipe
20+
IgxPivotGridFilterPipe,
21+
IgxPivotGridSortingPipe
2122
],
2223
exports: [
2324
IgxGridModule,
@@ -27,7 +28,8 @@ import { IgxPivotHeaderRowComponent } from './pivot-header-row.component';
2728
IgxPivotRowExpansionPipe,
2829
IgxPivotRowPipe,
2930
IgxPivotColumnPipe,
30-
IgxPivotGridFilterPipe
31+
IgxPivotGridFilterPipe,
32+
IgxPivotGridSortingPipe
3133
],
3234
imports: [
3335
IgxGridModule,

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

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,13 @@ import { DataUtil } from '../../data-operations/data-util';
44
import { FilteringExpressionsTree, IFilteringExpressionsTree } from '../../data-operations/filtering-expressions-tree';
55
import { IFilteringStrategy } from '../../data-operations/filtering-strategy';
66
import { IPivotConfiguration, IPivotDimension, IPivotKeys } from './pivot-grid.interface';
7-
import { PivotColumnDimensionsStrategy, PivotRowDimensionsStrategy } from '../../data-operations/pivot-strategy';
7+
import { DefaultPivotSortingStrategy, PivotColumnDimensionsStrategy, PivotRowDimensionsStrategy } from '../../data-operations/pivot-strategy';
88
import { PivotUtil } from './pivot-util';
99
import { FilteringLogic } from '../../data-operations/filtering-expression.interface';
10+
import { IGridSortingStrategy } from '../../data-operations/sorting-strategy';
11+
import { ISortingExpression } from '../../data-operations/sorting-expression.interface';
12+
import { GridBaseAPIService, IgxGridBaseDirective } from '../hierarchical-grid/public_api';
13+
import { GridType } from '../common/grid.interface';
1014
/**
1115
* @hidden
1216
*/
@@ -127,3 +131,37 @@ export class IgxPivotGridFilterPipe implements PipeTransform {
127131
return result;
128132
}
129133
}
134+
135+
/**
136+
* @hidden
137+
*/
138+
@Pipe({
139+
name: 'pivotGridSort',
140+
pure: true
141+
})
142+
export class IgxPivotGridSortingPipe implements PipeTransform {
143+
constructor(private gridAPI: GridBaseAPIService<IgxGridBaseDirective & GridType>) { }
144+
public transform(collection: any[], config: IPivotConfiguration, sorting: IGridSortingStrategy,
145+
id: string, pipeTrigger: number, pinned?): any[] {
146+
let result: any[];
147+
const allDimensions = config.rows;
148+
const enabledDimensions = allDimensions.filter(x => x && x.enabled);
149+
const expressions: ISortingExpression[] = [];
150+
PivotUtil.flatten(enabledDimensions).forEach(x => {
151+
if (x.sortDirection) {
152+
expressions.push({
153+
dir: x.sortDirection,
154+
fieldName: x.memberName,
155+
strategy: DefaultPivotSortingStrategy.instance()
156+
});
157+
}
158+
});
159+
if (!expressions.length) {
160+
result = collection;
161+
} else {
162+
result = DataUtil.sort(cloneArray(collection), expressions, sorting, this.gridAPI.grid);
163+
}
164+
165+
return result;
166+
}
167+
}

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

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,11 @@
1414
(dragOver)="onDimDragOver($event, 2)"
1515
(dragLeave)="onDimDragLeave($event)"
1616
(dragDrop)="onDimDrop($event, filterArea, 2)"
17+
(click)="onChipSort($event, filter)"
1718
>
1819
<igx-icon igxPrefix>filter_list</igx-icon>
1920
{{filter.memberName}}
21+
<igx-icon *ngIf="filter.sortDirection" igxSuffix> {{ filter.sortDirection < 2 ? 'arrow_upward' : 'arrow_downward' }}</igx-icon>
2022
</igx-chip>
2123
</igx-chips-area>
2224
</div>
@@ -30,13 +32,17 @@
3032
<!-- Columns area -->
3133
<igx-chips-area #colArea droppable='true' style="width:fit-content; height: 100%;">
3234
<igx-chip *ngFor="let col of grid.columnDimensions" [draggable]="'true'" [id]="col.memberName"
33-
[removable]="true" (remove)="columnRemoved($event)"
35+
[removable]="true" (remove)="columnRemoved($event)"
3436
(dragOver)="onDimDragOver($event, 1)"
3537
(dragLeave)="onDimDragLeave($event)"
36-
(dragDrop)="onDimDrop($event, colArea, 1)">
38+
(dragDrop)="onDimDrop($event, colArea, 1)"
39+
(click)="onChipSort($event, col)"
40+
>
3741
<igx-icon igxPrefix>view_column</igx-icon>
3842
<igx-icon igxPrefix>filter_list</igx-icon>
3943
{{col.memberName}}
44+
45+
<igx-icon *ngIf="col.sortDirection" igxSuffix> {{ col.sortDirection < 2 ? 'arrow_upward' : 'arrow_downward' }}</igx-icon>
4046
</igx-chip>
4147
</igx-chips-area>
4248
</div>
@@ -83,10 +89,12 @@
8389
[removable]="true" (remove)="rowRemoved($event)"
8490
(dragLeave)="onDimDragLeave($event)"
8591
(dragDrop)="onDimDrop($event, rowArea, 0)"
86-
(dragOver)="onDimDragOver($event, 0)">
92+
(dragOver)="onDimDragOver($event, 0)"
93+
(click)="onChipSort($event, row)">
8794
<igx-icon igxPrefix>table_rows</igx-icon>
8895
<igx-icon igxPrefix>filter_list</igx-icon>
8996
{{ row.memberName}}
97+
<igx-icon *ngIf="row.sortDirection" igxSuffix> {{ row.sortDirection < 2 ? 'arrow_upward' : 'arrow_downward' }}</igx-icon>
9098
</igx-chip>
9199
</igx-chips-area>
92100
</div>

projects/igniteui-angular/src/lib/grids/pivot-grid/pivot-header-row.component.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,10 @@ import {
77
Renderer2
88
} from '@angular/core';
99
import { IBaseChipEventArgs } from '../../chips/chip.component';
10+
import { SortingDirection } from '../../data-operations/sorting-expression.interface';
1011
import { IgxGridHeaderRowComponent } from '../headers/grid-header-row.component';
1112
import { DropPosition } from '../moving/moving.service';
12-
import { PivotDimensionType } from './pivot-grid.interface';
13+
import { IPivotDimension, PivotDimensionType } from './pivot-grid.interface';
1314
import { IgxPivotRowComponent } from './pivot-row.component';
1415

1516
export interface IgxGridRowSelectorsTemplateContext {
@@ -75,6 +76,21 @@ export class IgxPivotHeaderRowComponent extends IgxGridHeaderRowComponent {
7576
filter.enabled = false;
7677
}
7778

79+
public onChipSort(event, dimension: IPivotDimension) {
80+
if (!dimension.sortDirection) {
81+
dimension.sortDirection = SortingDirection.None;
82+
}
83+
dimension.sortDirection = dimension.sortDirection + 1 > SortingDirection.Desc ?
84+
SortingDirection.None : dimension.sortDirection + 1;
85+
// apply same sort direction to children.
86+
let dim = dimension;
87+
while(dim.childLevel) {
88+
dim.childLevel.sortDirection = dimension.sortDirection;
89+
dim = dim.childLevel;
90+
}
91+
this.grid.pipeTrigger++;
92+
}
93+
7894
public onDimDragOver(event, dimension?: PivotDimensionType) {
7995
const typeMismatch = dimension !== undefined ? this.grid.pivotConfiguration.values.find(x => x.member === event.dragChip.id) :
8096
!this.grid.pivotConfiguration.values.find(x => x.member === event.dragChip.id);

0 commit comments

Comments
 (0)