Skip to content

Commit 1f0e051

Browse files
authored
Merge pull request #6145 from IgniteUI/ddincheva/collapsibleGroups
Collapsible column groups
2 parents 4020a9b + 3dd2d82 commit 1f0e051

File tree

12 files changed

+288
-50
lines changed

12 files changed

+288
-50
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,12 @@ All notable changes for each version of this project will be documented in this
2929
- `sortingExpressionsChange` event emitter is added, which is fired whenever a change to the sorting expressions has occurred (prior to performing the actual sorting).
3030
- `filteringExpressionsTreeChange` event emitter is added, which is fired whenever a change to the filtering expressions has occurred (prior to performing the actual filtering).
3131
- `advancedFilteringExpressionsTreeChange` event emitter is added, which is fired whenever a change to the advanced filtering expressions has occurred (prior to performing the actual filtering).
32+
- `collapsible` and `expanded` properties are added to the IgxColumnGroupComponent; `collapsible` property identifies that certain column group is collapsible; `expanded` identifies whether the group is expanded or collapsed initially;
33+
- `collapsibleChange` and `expandedChange` events are added to the IgxColumnGroupComponent which are emited whenever `collapsible` and `expanded` properties are changed accordingly;
34+
- `visibleWhenCollapsed` property has been added to the IgxColumnComponent; Allows you to set whether the column stay visible when its parrent is collapsed.
35+
- `visibleWhenCollapsedChange` events is added to the IgxColumnComponent which are emited whenever `visibleWhenCollapsed` property is changed;
36+
- `collapsibleIndicatorTemplate` property is introduced to IgxColumnGroupComponent, which allows you to set a custom template for the expand collapse indicator;
37+
- `igxCollapsibleIndicator` directive has been introduced, which allows you to set a custom template for the expand collapse indicator;
3238
- `IgxGridExcelStyleFilteringComponent` and `IgxAdvancedFilteringDialogComponent` can now be hosted outside of the grid in order to provide the same experience as the built-in filtering UI.
3339
- `IgxOverlayService`:
3440
- `setOffset` method added. It offsets the content along the corresponding axis by the provided amount.

projects/igniteui-angular/src/lib/core/styles/components/grid/_grid-component.scss

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,18 @@
205205
@extend %grid-cell-header !optional;
206206
}
207207

208+
@include e(th-expander) {
209+
@extend %igx-grid__th-expander !optional
210+
}
211+
212+
@include e(th-group-title) {
213+
@extend %igx-grid__th-group-title !optional
214+
}
215+
216+
@include e(th, $m: collapsible) {
217+
@extend %igx-grid__th--collapsible !optional;
218+
}
219+
208220
@include e(th, $m: sortable) {
209221
@extend %igx-grid__th--sortable !optional;
210222
}

projects/igniteui-angular/src/lib/core/styles/components/grid/_grid-theme.scss

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1335,6 +1335,33 @@
13351335
}
13361336
}
13371337

1338+
1339+
%igx-grid__th-expander {
1340+
display: flex;
1341+
align-items: center;
1342+
justify-content: center;
1343+
margin-#{$right}: rem(8px);
1344+
cursor: pointer;
1345+
1346+
igx-icon {
1347+
color: --var($theme, 'expand-icon-color');
1348+
}
1349+
1350+
&:hover {
1351+
igx-icon {
1352+
color: --var($theme, 'expand-icon-hover-color');
1353+
}
1354+
}
1355+
}
1356+
1357+
%igx-grid__th-group-title {
1358+
@include ellipsis();
1359+
}
1360+
1361+
%igx-grid__th--collapsible {
1362+
justify-content: normal;
1363+
}
1364+
13381365
%igx-grid__th--sortable {
13391366
&:hover {
13401367
cursor: pointer;

projects/igniteui-angular/src/lib/grids/columns/column-group.component.ts

Lines changed: 75 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,54 @@ export class IgxColumnGroupComponent extends IgxColumnComponent implements After
2626

2727
@ContentChildren(IgxColumnComponent, { read: IgxColumnComponent })
2828
children = new QueryList<IgxColumnComponent>();
29+
30+
/**
31+
* Set if the column group is collapsible.
32+
* Default value is `false`
33+
* ```html
34+
* <igx-column-group [collapsible] = "true"></igx-column-group>
35+
* ```
36+
* @memberof IgxColumnGroupComponent
37+
*/
38+
@Input()
39+
public set collapsible(value: boolean) {
40+
this._collapsible = value;
41+
this.collapsibleChange.emit(this._collapsible);
42+
if (this.children && !this.hidden) {
43+
if (this._collapsible) {
44+
this.setExpandCollapseState();
45+
} else {
46+
this.children.forEach(child => child.hidden = false);
47+
}
48+
}
49+
}
50+
public get collapsible() {
51+
return this._collapsible && this.checkCollapsibleState();
52+
}
53+
54+
/**
55+
* Set whether the group is expanded or collapsed initially.
56+
* Applied only if the collapsible property is set to `true`
57+
* Default value is `true`
58+
* ```html
59+
* const state = false
60+
* <igx-column-group [(expand)] = "state"></igx-column-group>
61+
* ```
62+
* @memberof IgxColumnGroupComponent
63+
*/
64+
@Input()
65+
public set expanded(value: boolean) {
66+
if (!this.collapsible) { return; }
67+
this._expanded = value;
68+
this.expandedChange.emit(this._expanded);
69+
if (!this.hidden && this.children) {
70+
this.setExpandCollapseState();
71+
}
72+
}
73+
public get expanded() {
74+
return this._expanded;
75+
}
76+
2977
/**
3078
* Gets the column group `summaries`.
3179
* ```typescript
@@ -93,6 +141,18 @@ export class IgxColumnGroupComponent extends IgxColumnComponent implements After
93141
*/
94142
set bodyTemplate(template: TemplateRef<any>) { }
95143

144+
/**
145+
* Allows you to define a custom template for expand/collapse indicator
146+
* @memberof IgxColumnGroupComponent
147+
*/
148+
@Input()
149+
get collapsibleIndicatorTemplate(): TemplateRef<any> {
150+
return this._collapseIndicatorTemplate;
151+
}
152+
set collapsibleIndicatorTemplate(template: TemplateRef<any>) {
153+
this._collapseIndicatorTemplate = template;
154+
}
155+
96156
/**
97157
* Returns a reference to the inline editor template.
98158
* ```typescript
@@ -143,7 +203,14 @@ export class IgxColumnGroupComponent extends IgxColumnComponent implements After
143203
set hidden(value: boolean) {
144204
this._hidden = value;
145205
this.hiddenChange.emit(this._hidden);
146-
this.children.forEach(child => child.hidden = value);
206+
if (this._hidden || !this.collapsible) {
207+
this.children.forEach(child => child.hidden = this._hidden);
208+
} else {
209+
this.children.forEach(c => {
210+
if (c.visibleWhenCollapsed === undefined) {c.hidden = false; return; }
211+
c.hidden = this.expanded ? c.visibleWhenCollapsed : !c.visibleWhenCollapsed;
212+
});
213+
}
147214
}
148215

149216
/**
@@ -163,14 +230,21 @@ export class IgxColumnGroupComponent extends IgxColumnComponent implements After
163230
if (this.headTemplate && this.headTemplate.length) {
164231
this._headerTemplate = this.headTemplate.toArray()[0].template;
165232
}
233+
if (this.collapseIndicatorTemplate) {
234+
this._collapseIndicatorTemplate = this.collapseIndicatorTemplate.template;
235+
}
166236
// currently only ivy fixes the issue, we have to slice only if the first child is group
167237
if (this.children.first === this) {
168238
this.children.reset(this.children.toArray().slice(1));
169239
}
170240
this.children.forEach(child => {
171241
child.parent = this;
172242
});
243+
if (this.collapsible) {
244+
this.setExpandCollapseState();
245+
}
173246
}
247+
174248
/**
175249
* Returns the children columns collection.
176250
* ```typescript

projects/igniteui-angular/src/lib/grids/columns/column.component.ts

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ import {
4040
IgxCellTemplateDirective,
4141
IgxCellHeaderTemplateDirective,
4242
IgxCellEditorTemplateDirective,
43+
IgxCollapsibleIndicatorTemplateDirective,
4344
IgxFilterCellTemplateDirective
4445
} from './templates.directive';
4546
import { MRLResizeColumnInfo, MRLColumnSizeInfo } from './interfaces';
@@ -259,6 +260,18 @@ export class IgxColumnComponent implements AfterContentInit {
259260
*/
260261
@Output()
261262
public hiddenChange = new EventEmitter<boolean>();
263+
264+
/** @hidden */
265+
@Output()
266+
public expandedChange = new EventEmitter<boolean>();
267+
268+
/** @hidden */
269+
@Output()
270+
public collapsibleChange = new EventEmitter<boolean>();
271+
/** @hidden */
272+
@Output()
273+
public visibleWhenCollapsedChange = new EventEmitter<boolean>();
274+
262275
/**
263276
* Gets whether the hiding is disabled.
264277
* ```typescript
@@ -858,6 +871,10 @@ export class IgxColumnComponent implements AfterContentInit {
858871
set filterCellTemplate(template: TemplateRef<any>) {
859872
this._filterCellTemplate = template;
860873
}
874+
875+
/** @hidden */
876+
@Input('collapsibleIndicatorTemplate')
877+
public collapsibleIndicatorTemplate: TemplateRef<any>;
861878
/**
862879
* Gets the cells of the column.
863880
* ```typescript
@@ -1026,6 +1043,39 @@ export class IgxColumnComponent implements AfterContentInit {
10261043
*/
10271044
@Input() colStart: number;
10281045

1046+
/**
1047+
* Indicates whether the column will be visible when its parent is collapsed.
1048+
* ```html
1049+
* <igx-column-group>
1050+
* <igx-column [visibleWhenCollapsed]="true"></igx-column>
1051+
* </igx-column-group>
1052+
* ```
1053+
* @memberof IgxColumnComponent
1054+
*/
1055+
@notifyChanges(true)
1056+
@Input()
1057+
set visibleWhenCollapsed(value: boolean) {
1058+
this._visibleWhenCollapsed = value;
1059+
this.visibleWhenCollapsedChange.emit(this._visibleWhenCollapsed);
1060+
if (this.parent) { this.parent.setExpandCollapseState(); }
1061+
}
1062+
1063+
get visibleWhenCollapsed(): boolean {
1064+
return this._visibleWhenCollapsed;
1065+
}
1066+
1067+
/**
1068+
* @hidden
1069+
* @internal
1070+
*/
1071+
public collapsible = false;
1072+
1073+
/**
1074+
* @hidden
1075+
* @internal
1076+
*/
1077+
public expanded = true;
1078+
10291079
/**
10301080
* hidden
10311081
*/
@@ -1093,6 +1143,10 @@ export class IgxColumnComponent implements AfterContentInit {
10931143
*@hidden
10941144
*/
10951145
protected _filterCellTemplate: TemplateRef<any>;
1146+
/**
1147+
*@hidden
1148+
*/
1149+
protected _collapseIndicatorTemplate: TemplateRef<any>;
10961150
/**
10971151
*@hidden
10981152
*/
@@ -1137,6 +1191,18 @@ export class IgxColumnComponent implements AfterContentInit {
11371191
* @hidden
11381192
*/
11391193
protected _editable: boolean;
1194+
/**
1195+
* @hidden
1196+
*/
1197+
protected _visibleWhenCollapsed;
1198+
/**
1199+
* @hidden
1200+
*/
1201+
protected _collapsible = false;
1202+
/**
1203+
* @hidden
1204+
*/
1205+
protected _expanded = true;
11401206
/**
11411207
* @hidden
11421208
*/
@@ -1165,6 +1231,11 @@ export class IgxColumnComponent implements AfterContentInit {
11651231
*/
11661232
@ContentChild(IgxFilterCellTemplateDirective, { read: IgxFilterCellTemplateDirective, static: false })
11671233
public filterCellTemplateDirective: IgxFilterCellTemplateDirective;
1234+
/**
1235+
*@hidden
1236+
*/
1237+
@ContentChild(IgxCollapsibleIndicatorTemplateDirective, { read: IgxCollapsibleIndicatorTemplateDirective, static: false })
1238+
protected collapseIndicatorTemplate: IgxCollapsibleIndicatorTemplateDirective;
11681239

11691240
constructor(public gridAPI: GridBaseAPIService<IgxGridBaseDirective & GridType>, public cdr: ChangeDetectorRef,
11701241
public rowIslandAPI: IgxRowIslandAPIService) { }
@@ -1717,6 +1788,26 @@ export class IgxColumnComponent implements AfterContentInit {
17171788
this.calcPixelWidth = parseInt(this._calcWidth, 10);
17181789
}
17191790

1791+
/**
1792+
* @hidden
1793+
* @internal
1794+
*/
1795+
protected setExpandCollapseState() {
1796+
this.children.filter(col => (col.visibleWhenCollapsed !== undefined)).forEach(c => {
1797+
if (!this.collapsible) { c.hidden = this.hidden; return; }
1798+
c.hidden = this._expanded ? c.visibleWhenCollapsed : !c.visibleWhenCollapsed;
1799+
});
1800+
}
1801+
/**
1802+
* @hidden
1803+
* @internal
1804+
*/
1805+
protected checkCollapsibleState() {
1806+
if (!this.children) { return false; }
1807+
const cols = this.children.map(child => child.visibleWhenCollapsed);
1808+
return (cols.some(c => c === true) && cols.some(c => c === false));
1809+
}
1810+
17201811
/**
17211812
*@hidden
17221813
*/

projects/igniteui-angular/src/lib/grids/columns/column.module.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
IgxCellFooterTemplateDirective,
88
IgxCellHeaderTemplateDirective,
99
IgxCellTemplateDirective,
10+
IgxCollapsibleIndicatorTemplateDirective,
1011
IgxFilterCellTemplateDirective
1112
} from './templates.directive';
1213

@@ -18,6 +19,7 @@ import {
1819
IgxCellHeaderTemplateDirective,
1920
IgxCellFooterTemplateDirective,
2021
IgxCellEditorTemplateDirective,
22+
IgxCollapsibleIndicatorTemplateDirective,
2123
IgxColumnComponent,
2224
IgxColumnGroupComponent,
2325
IgxColumnLayoutComponent
@@ -33,6 +35,7 @@ import {
3335
IgxCellHeaderTemplateDirective,
3436
IgxCellFooterTemplateDirective,
3537
IgxCellEditorTemplateDirective,
38+
IgxCollapsibleIndicatorTemplateDirective,
3639
IgxColumnComponent,
3740
IgxColumnGroupComponent,
3841
IgxColumnLayoutComponent

projects/igniteui-angular/src/lib/grids/columns/templates.directive.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,3 +42,11 @@ export class IgxCellEditorTemplateDirective {
4242

4343
constructor(public template: TemplateRef<any>) { }
4444
}
45+
46+
@Directive({
47+
selector: '[igxCollapsibleIndicator]'
48+
})
49+
export class IgxCollapsibleIndicatorTemplateDirective {
50+
51+
constructor(public template: TemplateRef<any>) { }
52+
}

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

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,18 +20,35 @@
2020
<span *ngIf="grid.hasMovableColumns" class="igx-grid__th-drop-indicator-right"></span>
2121
</ng-container>
2222

23+
2324
<ng-template #defaultColumn>
24-
<span [attr.title]="column.header">{{column.header}}</span>
25+
<span class="igx-grid__th-group-title" [attr.title]="column.header">{{column.header}}</span>
26+
</ng-template>
27+
28+
<ng-template #defaultCollapseIndicator>
29+
<igx-icon [attr.draggable]="false" >
30+
{{column.expanded ? 'expand_more' : 'chevron_right'}} </igx-icon>
2531
</ng-template>
2632

2733
<ng-container *ngIf="!grid.hasColumnLayouts && column.columnGroup">
2834
<span *ngIf="grid.hasMovableColumns" class="igx-grid__th-drop-indicator-left"></span>
2935
<div class="igx-grid__thead-title"
30-
[ngClass]="{'igx-grid__th--pinned-last': hasLastPinnedChildColumn}"
36+
role="columnheader"
37+
[attr.aria-label]="column.header || column.field"
38+
[attr.aria-expanded]="column.expanded"
39+
tabindex="0"
40+
[ngClass]="{'igx-grid__th--pinned-last': hasLastPinnedChildColumn, 'igx-grid__th--collapsible': column.collapsible}"
3141
[igxColumnMovingDrag]="column"
3242
[ghostHost]="grid.outletDirective.nativeElement"
3343
[attr.droppable]="true"
3444
[igxColumnMovingDrop]="column">
45+
<ng-container *ngIf="column.collapsible">
46+
<div class="igx-grid__th-expander" (click)="column.expanded = !column.expanded">
47+
<ng-container
48+
*ngTemplateOutlet="column.collapsibleIndicatorTemplate ? column.collapsibleIndicatorTemplate : defaultCollapseIndicator; context: {$implicit: column, column: column}">
49+
</ng-container>
50+
</div>
51+
</ng-container>
3552
<ng-container *ngTemplateOutlet="column.headerTemplate ? column.headerTemplate : defaultColumn; context: { $implicit: column, column: column}">
3653
</ng-container>
3754
</div>

0 commit comments

Comments
 (0)