Skip to content

Commit 4581b5d

Browse files
igdmdimitrovgedinakovaDiyanDimitrov
authored
tree grid grouping pipe and group area (#9625)
* feat(grid): extracted column grouping area into a separate component * feat(tg-grouping): added tree grid grouping pipe * feat(tg-group-area): 2 group area components for tree grid and regular grid Co-authored-by: Galina Edinakova <[email protected]> Co-authored-by: Diyan Dimitrov <[email protected]>
1 parent 3adfb21 commit 4581b5d

30 files changed

+1456
-178
lines changed

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,7 @@ export class IgxSorting implements IGridSortingStrategy {
234234

235235
export class IgxDataRecordSorting extends IgxSorting {
236236

237-
protected getFieldValue(obj: any, key: string, isDate: boolean = false): any {
238-
return isDate ? parseDate(resolveNestedPath(obj.data, key)) : resolveNestedPath(obj.data, key);
237+
protected getFieldValue(obj: any, key: string, isDate: boolean = false, isTime: boolean = false): any {
238+
return super.getFieldValue(obj.data, key, isDate, isTime);
239239
}
240240
}

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

+7-1
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@ import { IGridResourceStrings } from '../../core/i18n/grid-resources';
66
import { ISortingExpression } from '../../data-operations/sorting-expression.interface';
77
import { IGroupingExpression } from '../../data-operations/grouping-expression.interface';
88
import { TransactionService, Transaction, State } from '../../services/public_api';
9-
import { ITreeGridRecord } from '../tree-grid/public_api';
9+
import { IgxColumnComponent, ITreeGridRecord } from '../tree-grid/public_api';
1010
import { IGroupByRecord } from '../../data-operations/groupby-record.interface';
11+
import { IGroupByExpandState } from '../../data-operations/groupby-expand-state.interface';
1112

1213
export interface IGridDataBindable {
1314
data: any[] | null;
@@ -30,6 +31,8 @@ export interface GridType extends IGridDataBindable {
3031
id: string;
3132
renderedRowHeight: number;
3233
summaryPipeTrigger: number;
34+
draggedColumn: IgxColumnComponent;
35+
hasColumnLayouts: boolean;
3336

3437
filterMode: FilterMode;
3538

@@ -81,9 +84,12 @@ export interface GridType extends IGridDataBindable {
8184
* An interface describing a Flat Grid type
8285
*/
8386
export interface FlatGridType extends GridType {
87+
groupingExpansionState: IGroupByExpandState[];
8488
groupingExpressions: IGroupingExpression[];
8589
groupingExpressionsChange: EventEmitter<IGroupingExpression[]>;
8690
toggleGroup(groupRow: IGroupByRecord): void;
91+
clearGrouping(field: string): void;
92+
groupBy(expression: IGroupingExpression | Array<IGroupingExpression>): void;
8793
}
8894

8995
/**

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

-4
Original file line numberDiff line numberDiff line change
@@ -2644,10 +2644,6 @@ export abstract class IgxGridBaseDirective extends DisplayDensityBase implements
26442644
* @hidden @internal
26452645
*/
26462646
public tfootHeight: number;
2647-
/**
2648-
* @hidden @internal
2649-
*/
2650-
public chipsGoupingExpressions = [];
26512647
/**
26522648
* @hidden @internal
26532649
*/

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

+9-1
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,14 @@ import { IgxGridFilteringModule } from './filtering/base/filtering.module';
3131
import { IgxRowDirective } from './row.directive';
3232
import {
3333
IgxExcelStyleHeaderIconDirective,
34+
IgxGroupAreaDropDirective,
3435
IgxHeaderCollapseIndicatorDirective,
3536
IgxHeaderExpandIndicatorDirective,
3637
IgxRowCollapsedIndicatorDirective,
3738
IgxRowExpandedIndicatorDirective
3839
} from './grid/grid.directives';
40+
import { IgxChipsModule } from '../chips/chips.module';
41+
import { IgxGroupByMetaPipe } from './grouping/group-by-area.directive';
3942
/**
4043
* @hidden
4144
*/
@@ -56,6 +59,8 @@ import {
5659
IgxHeaderExpandIndicatorDirective,
5760
IgxHeaderCollapseIndicatorDirective,
5861
IgxExcelStyleHeaderIconDirective,
62+
IgxGroupAreaDropDirective,
63+
IgxGroupByMetaPipe
5964
],
6065
entryComponents: [
6166
IgxAdvancedFilteringDialogComponent
@@ -89,6 +94,8 @@ import {
8994
IgxHeaderExpandIndicatorDirective,
9095
IgxHeaderCollapseIndicatorDirective,
9196
IgxExcelStyleHeaderIconDirective,
97+
IgxGroupAreaDropDirective,
98+
IgxGroupByMetaPipe
9299
],
93100
imports: [
94101
IgxGridColumnModule,
@@ -104,7 +111,8 @@ import {
104111
IgxGridExcelStyleFilteringModule,
105112
IgxRowDragModule,
106113
IgxPaginatorModule,
107-
IgxGridSharedModules
114+
IgxGridSharedModules,
115+
IgxChipsModule
108116
],
109117
providers: [
110118
{ provide: IgxGridTransaction, useClass: IgxBaseTransactionService }

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

+12-29
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,17 @@
11
<ng-content select="igx-grid-toolbar"></ng-content>
22

3-
<div [style.flex-basis.px]='outerWidth' class="igx-grid__grouparea"
4-
*ngIf="showGroupArea && (groupingExpressions.length > 0 || hasGroupableColumns)" #groupArea>
5-
<igx-chips-area (reorder)="chipsOrderChanged($event)" (moveEnd)="chipsMovingEnded()">
6-
<ng-container *ngFor="let expr of chipsGoupingExpressions; let last = last;">
7-
<igx-chip [id]="expr.fieldName" [title]="getGroupByChipTitle(expr)"
8-
[removable]="getColumnGroupable(expr.fieldName)"
9-
[draggable]="getColumnGroupable(expr.fieldName)" [displayDensity]="displayDensity"
10-
(keyDown)="onChipKeyDown($event)" (remove)="onChipRemoved($event)"
11-
(chipClick)="getColumnGroupable(expr.fieldName) ? onChipClicked($event): null"
12-
[disabled]='!getColumnGroupable(expr.fieldName)'>
13-
<span>{{ getGroupByChipTitle(expr) }}</span>
14-
<igx-icon igxSuffix>{{ expr.dir == 1 ? 'arrow_upward' : 'arrow_downward' }}</igx-icon>
15-
</igx-chip>
16-
<span class="igx-grid__grouparea-connector">
17-
<igx-icon [style.visibility]="(!last || dropAreaVisible) ? 'visible' : 'hidden'">arrow_forward
18-
</igx-icon>
19-
</span>
20-
</ng-container>
21-
<div igxGroupAreaDrop [style.visibility]="dropAreaVisible ? 'visible' : 'hidden'" [class]="groupAreaHostClass"
22-
[attr.gridId]='this.id'>
23-
<ng-container *ngTemplateOutlet="dropAreaTemplateResolved"></ng-container>
24-
</div>
25-
</igx-chips-area>
26-
</div>
3+
<!-- Group-by area -->
4+
<ng-container *ngIf="showGroupArea && (groupingExpressions.length > 0 || hasGroupableColumns)">
5+
<igx-grid-group-by-area #groupArea [style.flex-basis.px]='outerWidth'
6+
[grid]="this"
7+
[expressions]="groupingExpressions"
8+
[sortingExpressions]="sortingExpressions"
9+
[density]="displayDensity"
10+
[dropAreaTemplate]="dropAreaTemplate"
11+
[dropAreaMessage]="dropAreaMessage"
12+
>
13+
</igx-grid-group-by-area>
14+
</ng-container>
2715

2816
<div class="igx-grid__thead" role="rowgroup">
2917
<div class="igx-grid__thead-wrapper" (keydown.meta.c)="copyHandler($event)" (keydown.control.c)="copyHandler($event)" (copy)="copyHandler($event)"
@@ -282,11 +270,6 @@
282270
</div>
283271
</ng-template>
284272

285-
<ng-template #defaultDropArea>
286-
<igx-icon class="igx-drop-area__icon">group_work</igx-icon>
287-
<span class="igx-drop-area__text">{{dropAreaMessage}}</span>
288-
</ng-template>
289-
290273
<ng-template #defaultExpandedTemplate>
291274
<igx-icon role="button" class="igx-grid__group-expand-btn"
292275
[ngClass]="{

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

+5-110
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import {
22
Component, ChangeDetectionStrategy, Input, Output, EventEmitter, ContentChild, ViewChildren,
3-
QueryList, ViewChild, ElementRef, TemplateRef, DoCheck, AfterContentInit, HostBinding,
3+
QueryList, ViewChild, TemplateRef, DoCheck, AfterContentInit, HostBinding,
44
forwardRef, OnInit, AfterViewInit, ContentChildren
55
} from '@angular/core';
66
import { GridBaseAPIService } from '../api.service';
@@ -14,8 +14,6 @@ import { IgxGroupByRowTemplateDirective, IgxGridDetailTemplateDirective } from '
1414
import { IgxGridGroupByRowComponent } from './groupby-row.component';
1515
import { IGroupByExpandState } from '../../data-operations/groupby-expand-state.interface';
1616
import { IForOfState } from '../../directives/for-of/for_of.directive';
17-
import { IBaseChipEventArgs, IChipClickEventArgs, IChipKeyDownEventArgs } from '../../chips/chip.component';
18-
import { IChipsAreaReorderEventArgs } from '../../chips/chips-area.component';
1917
import { IgxColumnComponent } from '../columns/column.component';
2018
import { takeUntil } from 'rxjs/operators';
2119
import { IgxFilteringService } from '../filtering/grid-filtering.service';
@@ -25,12 +23,13 @@ import { IgxGridSummaryService } from '../summaries/grid-summary.service';
2523
import { IgxGridSelectionService } from '../selection/selection.service';
2624
import { IgxForOfSyncService, IgxForOfScrollSyncService } from '../../directives/for-of/for_of.sync.service';
2725
import { IgxGridMRLNavigationService } from '../grid-mrl-navigation.service';
28-
import { FilterMode, RowPinningPosition } from '../common/enums';
26+
import { FilterMode } from '../common/enums';
2927
import { GridType } from '../common/grid.interface';
3028
import { IgxGroupByRowSelectorDirective } from '../selection/row-selectors';
3129
import { IgxGridCRUDService } from '../common/crud.service';
3230
import { IgxGridRow, IgxGroupByRow, IgxSummaryRow } from '../grid-public-row';
3331
import { RowType } from '../common/row.interface';
32+
import { IgxGridGroupByAreaComponent } from '../grouping/grid-group-by-area.component';
3433

3534
let NEXT_ID = 0;
3635

@@ -156,17 +155,11 @@ export class IgxGridComponent extends IgxGridBaseDirective implements GridType,
156155
@ContentChild(IgxGridDetailTemplateDirective, { read: TemplateRef, static: false })
157156
public detailTemplate: TemplateRef<any> = null;
158157

159-
/**
160-
* @hidden @internal
161-
*/
162-
@ViewChild('defaultDropArea', { read: TemplateRef, static: true })
163-
public defaultDropAreaTemplate: TemplateRef<any>;
164-
165158
/**
166159
* @hidden @internal
167160
*/
168161
@ViewChild('groupArea')
169-
public groupArea: ElementRef;
162+
public groupArea: IgxGridGroupByAreaComponent;
170163

171164
/**
172165
* @hidden @internal
@@ -371,7 +364,6 @@ export class IgxGridComponent extends IgxGridBaseDirective implements GridType,
371364
const newExpressions: IGroupingExpression[] = value;
372365
this._groupingExpressions = cloneArray(value);
373366
this.groupingExpressionsChange.emit(this._groupingExpressions);
374-
this.chipsGoupingExpressions = cloneArray(value);
375367
if (this._gridAPI.grid) {
376368
/* grouping should work in conjunction with sorting
377369
and without overriding separate sorting expressions */
@@ -572,12 +564,6 @@ export class IgxGridComponent extends IgxGridBaseDirective implements GridType,
572564
public isDetailActive(rowIndex) {
573565
return this.navigation.activeNode ? this.navigation.activeNode.row === rowIndex : false;
574566
}
575-
/**
576-
* @hidden @internal
577-
*/
578-
public get groupAreaHostClass(): string {
579-
return this.getComponentDensityClass('igx-drop-area');
580-
}
581567

582568
/**
583569
* Gets/Sets the template reference for the group row.
@@ -812,7 +798,7 @@ export class IgxGridComponent extends IgxGridBaseDirective implements GridType,
812798
*/
813799
public get dropAreaVisible(): boolean {
814800
return (this.draggedColumn && this.draggedColumn.groupable) ||
815-
!this.chipsGoupingExpressions.length;
801+
!this.groupingExpressions.length;
816802
}
817803

818804
/**
@@ -878,89 +864,6 @@ export class IgxGridComponent extends IgxGridBaseDirective implements GridType,
878864
}
879865
}
880866

881-
/**
882-
* @hidden @internal
883-
*/
884-
public onChipRemoved(event: IBaseChipEventArgs) {
885-
this.clearGrouping(event.owner.id);
886-
}
887-
888-
/**
889-
* @hidden @internal
890-
*/
891-
public chipsOrderChanged(event: IChipsAreaReorderEventArgs) {
892-
const newGrouping = [];
893-
for (const chip of event.chipsArray) {
894-
const expr = this.groupingExpressions.filter((item) => item.fieldName === chip.id)[0];
895-
896-
if (!this.getColumnByName(expr.fieldName).groupable) {
897-
// disallow changing order if there are columns with groupable: false
898-
return;
899-
}
900-
newGrouping.push(expr);
901-
}
902-
this.groupingExpansionState = [];
903-
this.chipsGoupingExpressions = newGrouping;
904-
905-
if (event.originalEvent instanceof KeyboardEvent) {
906-
// When reordered using keyboard navigation, we don't have `onMoveEnd` event.
907-
this.groupingExpressions = this.chipsGoupingExpressions;
908-
}
909-
this.notifyChanges();
910-
}
911-
912-
/**
913-
* @hidden @internal
914-
*/
915-
public chipsMovingEnded() {
916-
this.groupingExpressions = this.chipsGoupingExpressions;
917-
this.notifyChanges();
918-
}
919-
920-
/**
921-
* @hidden @internal
922-
*/
923-
public onChipClicked(event: IChipClickEventArgs) {
924-
const sortingExpr = this.sortingExpressions;
925-
const columnExpr = sortingExpr.find((expr) => expr.fieldName === event.owner.id);
926-
const groupExpr = this.groupingExpressions.find((expr) => expr.fieldName === event.owner.id);
927-
columnExpr.dir = 3 - columnExpr.dir;
928-
groupExpr.dir = columnExpr.dir;
929-
this.sort(columnExpr);
930-
this.notifyChanges();
931-
}
932-
933-
/**
934-
* @hidden @internal
935-
*/
936-
public onChipKeyDown(event: IChipKeyDownEventArgs) {
937-
if (event.originalEvent.key === ' ' || event.originalEvent.key === 'Spacebar' || event.originalEvent.key === 'Enter') {
938-
const sortingExpr = this.sortingExpressions;
939-
const columnExpr = sortingExpr.find((expr) => expr.fieldName === event.owner.id);
940-
columnExpr.dir = 3 - columnExpr.dir;
941-
this.sort(columnExpr);
942-
this.notifyChanges();
943-
}
944-
}
945-
946-
/**
947-
* @hidden @internal
948-
*/
949-
public get dropAreaTemplateResolved(): TemplateRef<any> {
950-
if (this.dropAreaTemplate) {
951-
return this.dropAreaTemplate;
952-
} else {
953-
return this.defaultDropAreaTemplate;
954-
}
955-
}
956-
957-
/**
958-
* @hidden @internal
959-
*/
960-
public getGroupByChipTitle(expression: IGroupingExpression): string {
961-
const column = this.getColumnByName(expression.fieldName);
962-
return (column && column.header) || expression.fieldName;
963-
}
964867
/**
965868
* @hidden @internal
966869
*/
@@ -972,14 +875,6 @@ export class IgxGridComponent extends IgxGridBaseDirective implements GridType,
972875
}
973876
}
974877

975-
/**
976-
* @hidden @internal
977-
*/
978-
public getColumnGroupable(fieldName: string): boolean {
979-
const column = this.getColumnByName(fieldName);
980-
return column && column.groupable;
981-
}
982-
983878
/**
984879
* @hidden @internal
985880
*/

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

+10-20
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ import { Directive, ElementRef, Renderer2, NgZone, HostBinding, TemplateRef } fr
22
import { IgxDropDirective } from '../../directives/drag-drop/drag-drop.directive';
33
import { IgxColumnComponent } from '../columns/column.component';
44
import { IgxGridComponent } from './grid.component';
5-
import { SortingDirection } from '../../data-operations/sorting-expression.interface';
65
import { IgxColumnMovingDragDirective } from '../moving/moving.drag.directive';
6+
import { IgxGroupByAreaDirective } from '../grouping/group-by-area.directive';
77

88
/**
99
* @hidden
@@ -83,7 +83,11 @@ export class IgxGroupAreaDropDirective extends IgxDropDirective {
8383
@HostBinding('class.igx-drop-area--hover')
8484
public hovered = false;
8585

86-
constructor(private elementRef: ElementRef, private renderer: Renderer2, private zone: NgZone) {
86+
constructor(
87+
private groupArea: IgxGroupByAreaDirective,
88+
private elementRef: ElementRef,
89+
renderer: Renderer2,
90+
zone: NgZone) {
8791
super(elementRef, renderer, zone);
8892
}
8993

@@ -93,8 +97,10 @@ export class IgxGroupAreaDropDirective extends IgxDropDirective {
9397
if (!this.columnBelongsToGrid(column)) {
9498
return;
9599
}
96-
const grid = column.grid as IgxGridComponent;
97-
const isGrouped = grid.groupingExpressions.findIndex((item) => item.fieldName === column.field) !== -1;
100+
101+
const isGrouped = this.groupArea.expressions
102+
? this.groupArea.expressions.findIndex((item) => item.fieldName === column.field) !== -1
103+
: false;
98104
if (column.groupable && !isGrouped && !column.columnGroup && !!column.field) {
99105
drag.icon.innerText = 'group_work';
100106
this.hovered = true;
@@ -114,22 +120,6 @@ export class IgxGroupAreaDropDirective extends IgxDropDirective {
114120
this.hovered = false;
115121
}
116122

117-
public onDragDrop(event) {
118-
const drag: IgxColumnMovingDragDirective = event.detail.owner;
119-
if (drag instanceof IgxColumnMovingDragDirective) {
120-
const column: IgxColumnComponent = drag.column;
121-
if (!this.columnBelongsToGrid(column)) {
122-
return;
123-
}
124-
const grid = column.grid as IgxGridComponent;
125-
const isGrouped = grid.groupingExpressions.findIndex((item) => item.fieldName === column.field) !== -1;
126-
if (column.groupable && !isGrouped && !column.columnGroup && !!column.field) {
127-
grid.groupBy({ fieldName: column.field, dir: SortingDirection.Asc, ignoreCase: column.sortingIgnoreCase,
128-
strategy: column.sortStrategy, groupingComparer: column.groupingComparer });
129-
}
130-
}
131-
}
132-
133123
private closestParentByAttr(elem, attr) {
134124
return elem.hasAttribute(attr) ?
135125
elem :

0 commit comments

Comments
 (0)