Skip to content

Commit 1f30f40

Browse files
MayaKirovaMKirova
andauthored
feat(igxGridState): Add support for persisting MRL columns. (#14926)
* feat(IgxState): Re-use matching columns for state. * chore(*): Update some of the tests. * chore(*): Set back changeDetectorRef so that internal props init correctly. * chore(*): Minor fix and updating tests. * chore(*): Add test for state persistance column reusal. * chore(*): Sort column keys in column group so order doesn't matter. * chore(*): Update tests with sorted keys. * feat(igxGridState): Add support for persisting MRL columns. * chore(*): Add changelog entry. --------- Co-authored-by: MKirova <MKirova@DEV-MKIROVA>
1 parent f585aae commit 1f30f40

File tree

5 files changed

+150
-5
lines changed

5 files changed

+150
-5
lines changed

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ All notable changes for each version of this project will be documented in this
4141
- Added `activation` property to control tab selection. In `auto` mode (default), tabs are selected instantly with Arrow or Home/End keys. In `manual` mode, tabs are focused with keys but only selected with Enter or Space.
4242
- `IgxGridState`
4343
- When possible the state directive nows reuses the column that already exists on the grid when restoring the state, instead of creating new column instances every time. This removes the need to set any complex objects manually back on the column on `columnInit`. The only instance where this is still necessary is when the column (or its children in case of column groups) have no `field` property so there's no way to uniquely identify the matching column.
44-
44+
- Added support for persisting Multi-Row Layout.
4545
### Themes
4646
- `Palettes`
4747
- All palette colors have been migrated to the [CSS relative colors syntax](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_colors/Relative_colors). This means that color consumed as CSS variables no longer need to be wrapped in an `hsl` function.

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

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import { IPivotConfiguration, IPivotDimension } from './pivot-grid/pivot-grid.in
2222
import { PivotUtil } from './pivot-grid/pivot-util';
2323
import { IgxPivotDateDimension } from './pivot-grid/pivot-grid-dimensions';
2424
import { cloneArray, cloneValue } from '../core/utils';
25+
import { IgxColumnLayoutComponent } from './columns/column-layout.component';
2526

2627
export interface IGridState {
2728
columns?: IColumnState[];
@@ -92,6 +93,12 @@ export interface IColumnState {
9293
resizable: boolean;
9394
searchable: boolean;
9495
columnGroup: boolean;
96+
// mrl props
97+
columnLayout?: boolean;
98+
rowStart?: number,
99+
rowEnd?: number,
100+
colStart?: number;
101+
colEnd?: number,
95102
/**
96103
* @deprecated
97104
*/
@@ -213,6 +220,11 @@ export class IgxGridStateBaseDirective {
213220
key: c.columnGroup ? this.getColumnGroupKey(c) : c.field,
214221
parentKey: c.parent ? this.getColumnGroupKey(c.parent) : undefined,
215222
columnGroup: c.columnGroup,
223+
columnLayout: c.columnLayout || undefined,
224+
rowStart: c.parent?.columnLayout ? c.rowStart : undefined,
225+
rowEnd: c.parent?.columnLayout ? c.rowEnd : undefined,
226+
colStart: c.parent?.columnLayout ? c.colStart : undefined,
227+
colEnd: c.parent?.columnLayout ? c.colEnd : undefined,
216228
disableHiding: c.disableHiding,
217229
disablePinning: c.disablePinning,
218230
collapsible: c.columnGroup ? c.collapsible : undefined,
@@ -225,11 +237,15 @@ export class IgxGridStateBaseDirective {
225237
const newColumns = [];
226238
state.forEach((colState) => {
227239
const hasColumnGroup = colState.columnGroup;
240+
const hasColumnLayouts = colState.columnLayout;
228241
delete colState.columnGroup;
242+
delete colState.columnLayout;
229243
if (hasColumnGroup) {
230244
let ref1: IgxColumnGroupComponent = context.currGrid.columns.find(x => x.columnGroup && (colState.key ? this.getColumnGroupKey(x) === colState.key : x.header === colState.header)) as IgxColumnGroupComponent;
231245
if (!ref1) {
232-
const component = createComponent(IgxColumnGroupComponent, { environmentInjector: this.envInjector, elementInjector: this.injector });
246+
const component = hasColumnLayouts ?
247+
createComponent(IgxColumnLayoutComponent, { environmentInjector: this.envInjector, elementInjector: this.injector }) :
248+
createComponent(IgxColumnGroupComponent, { environmentInjector: this.envInjector, elementInjector: this.injector });
233249
ref1 = component.instance;
234250
component.changeDetectorRef.detectChanges();
235251
} else {

projects/igniteui-angular/src/lib/grids/state.directive.spec.ts

Lines changed: 72 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import { GridSelectionRange } from './common/types';
1818
import { CustomFilter } from '../test-utils/grid-samples.spec';
1919
import { IgxPaginatorComponent } from '../paginator/paginator.component';
2020
import { NgFor } from '@angular/common';
21-
import { IgxColumnComponent, IgxColumnGroupComponent, IgxGridDetailTemplateDirective } from './public_api';
21+
import { IgxColumnComponent, IgxColumnGroupComponent, IgxColumnLayoutComponent, IgxGridDetailTemplateDirective } from './public_api';
2222
import { IColumnState, IGridState } from './state-base.directive';
2323

2424
/* eslint-disable max-len */
@@ -774,6 +774,43 @@ describe('IgxGridState - input properties #grid', () => {
774774
gridState = state.getState(true, 'expansion');
775775
expect(gridState).toBe(expansionState);
776776
});
777+
778+
it('should correctly restore mrl column states.', () => {
779+
const fix = TestBed.createComponent(IgxGridMRLStateComponent);
780+
fix.detectChanges();
781+
const grid = fix.componentInstance.grid;
782+
const state = fix.componentInstance.state;
783+
784+
const gridColumnState = state.getState(false, 'columns') as IGridState;
785+
const group1 = gridColumnState.columns.find(x => x.field === 'group1');
786+
expect(group1.columnLayout).toBeTrue();
787+
788+
const prodId = gridColumnState.columns.find(x => x.field === 'ProductID');
789+
expect(prodId.columnLayout).toBeFalsy();
790+
expect(prodId.rowStart).toBe(1);
791+
expect(prodId.rowEnd).toBe(4);
792+
expect(prodId.colStart).toBe(1);
793+
expect(prodId.colEnd).toBe(1);
794+
795+
// apply change
796+
group1.pinned = true;
797+
prodId.pinned = true;
798+
799+
state.setState(gridColumnState, 'columns');
800+
fix.detectChanges();
801+
802+
const group1Column = grid.getColumnByName("group1");
803+
const prodIdColumn = grid.getColumnByName("ProductID");
804+
expect(group1Column.columnLayout).toBeTrue();
805+
expect(group1Column.pinned).toBeTrue();
806+
expect(prodIdColumn.pinned).toBeTrue();
807+
expect(prodIdColumn.columnLayoutChild).toBeTrue();
808+
expect(prodIdColumn.parent).toBe(group1Column);
809+
expect(prodIdColumn.rowStart).toBe(1);
810+
expect(prodIdColumn.rowEnd).toBe(4);
811+
expect(prodIdColumn.colStart).toBe(1);
812+
expect(prodIdColumn.colEnd).toBe(1);
813+
});
777814
});
778815

779816
class HelperFunctions {
@@ -975,5 +1012,39 @@ export class CollapsibleColumnGroupTestComponent {
9751012
public state: IgxGridStateDirective;
9761013
public data = SampleTestData.contactInfoDataFull();
9771014
}
1015+
1016+
@Component({
1017+
template: `
1018+
<igx-grid #grid [data]="data" igxGridState primaryKey="ProductID">
1019+
<igx-column-layout field='group1'>
1020+
<igx-column [groupable]="true" [rowStart]="1" [colStart]="1" [colEnd]="1" [rowEnd]="4" field="ProductID" [width]="'200px'" [resizable]="true">
1021+
</igx-column>
1022+
</igx-column-layout>
1023+
<igx-column-layout field='group2'>
1024+
<igx-column [rowStart]="1" [colStart]="1" [colEnd]="3" field="ProductName" [width]="'300px'" [resizable]="true">
1025+
</igx-column>
1026+
<igx-column [rowStart]="2" [colStart]="1" field="InStock" [width]="'300px'" [resizable]="true">
1027+
</igx-column>
1028+
<igx-column [rowStart]="2" [colStart]="2" field="UnitsInStock" [width]="'400px'" [resizable]="true">
1029+
</igx-column>
1030+
<igx-column [rowStart]="3" [colStart]="1" [colEnd]="3" field="OrderDate" [width]="'300px'" [resizable]="true">
1031+
</igx-column>
1032+
</igx-column-layout>
1033+
</igx-grid>
1034+
`,
1035+
standalone: true,
1036+
imports: [IgxGridComponent, IgxGridStateDirective, IgxColumnComponent, IgxColumnLayoutComponent]
1037+
})
1038+
export class IgxGridMRLStateComponent {
1039+
@ViewChild('grid', { read: IgxGridComponent, static: true })
1040+
public grid: IgxGridComponent;
1041+
1042+
@ViewChild(IgxGridStateDirective, { static: true })
1043+
public state: IgxGridStateDirective;
1044+
1045+
public data = SampleTestData.foodProductData();
1046+
}
1047+
1048+
9781049
/* eslint-enable max-len */
9791050

src/app/grid-state/grid-state.component.html

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,62 @@
108108
<div #reload="tooltip" igxTooltip>Reload the page.</div>
109109
</div>
110110

111+
<!-- IgxGrid with MRL-->
112+
<div class="grid__wrapper">
113+
<igx-expansion-panel #collapsibleComponent [collapsed]="true">
114+
<igx-expansion-panel-header [disabled]="false">
115+
<igx-expansion-panel-title>Multi-Row Layouts</igx-expansion-panel-title>
116+
<igx-expansion-panel-icon *ngIf="templatedIcon">
117+
{{collapsed() ? 'Expand':'Collapse'}}
118+
</igx-expansion-panel-icon>
119+
</igx-expansion-panel-header>
120+
<igx-expansion-panel-body>
121+
<ng-container *ngTemplateOutlet="controls; context: getContext(mrlGrid)"></ng-container>
122+
<igx-grid [id]="mrlGridId" #mrlGrid [igxGridState]="options" height="480px" [data]="localData"
123+
[allowFiltering]="true" [moving]="true">
124+
<igx-column-layout field='group1'>
125+
<ng-template igxHeader let-column>
126+
<span>Custom Header Template: {{column.field}}</span>
127+
</ng-template>
128+
<igx-column [groupable]="true" [rowStart]="1" [colStart]="1" [rowEnd]="4" field="EmployeeID" [width]="'200px'" [resizable]="true">
129+
<ng-template igxHeader let-column>
130+
<span>Custom Header Template: {{column.field}}</span>
131+
</ng-template>
132+
</igx-column>
133+
</igx-column-layout>
134+
<igx-column-layout field='group2'>
135+
<ng-template igxHeader let-column>
136+
<span>Custom Header Template: {{column.field}}</span>
137+
</ng-template>
138+
<igx-column [rowStart]="1" [colStart]="1" [colEnd]="3" field="FirstName" [width]="'300px'" [resizable]="true">
139+
<ng-template igxHeader let-column>
140+
<span>Custom Header Template: {{column.field}}</span>
141+
</ng-template>
142+
</igx-column>
143+
<igx-column [rowStart]="2" [colStart]="1" field="LastName" [width]="'300px'" [resizable]="true">
144+
<ng-template igxHeader let-column>
145+
<span>Custom Header Template: {{column.field}}</span>
146+
</ng-template>
147+
</igx-column>
148+
<igx-column [rowStart]="2" [colStart]="2" field="Country" [width]="'400px'" [resizable]="true">
149+
<ng-template igxHeader let-column>
150+
<span>Custom Header Template: {{column.field}}</span>
151+
</ng-template>
152+
</igx-column>
153+
<igx-column [rowStart]="3" [colStart]="1" [colEnd]="3" field="Age" [width]="'300px'" [resizable]="true">
154+
<ng-template igxHeader let-column>
155+
<span>Custom Header Template: {{column.field}}</span>
156+
</ng-template>
157+
</igx-column>
158+
</igx-column-layout>
159+
</igx-grid>
160+
</igx-expansion-panel-body>
161+
</igx-expansion-panel>
162+
163+
<div #clear="tooltip" igxTooltip>Clear the state from localStorage.</div>
164+
<div #reload="tooltip" igxTooltip>Reload the page.</div>
165+
</div>
166+
111167
<!-- IgxHierarchicalGrid -->
112168
<div class="grid__wrapper">
113169
<igx-expansion-panel #collapsibleComponent [collapsed]="true">

src/app/grid-state/grid-state.component.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ import { TREEGRID_FLAT_DATA, EMPLOYEE_DATA, employeesData } from './data';
99
import { FilteringExpressionsTree, FilteringLogic,
1010
IgxNumberSummaryOperand, IgxSummaryResult, IGridState, IgxGridStateDirective,
1111
IgxExpansionPanelComponent, IgxCellHeaderTemplateDirective,
12-
IGridStateOptions, GridFeatures, GridColumnDataType, IgxColumnComponent, GridType, IgxExpansionPanelHeaderComponent, IgxExpansionPanelTitleDirective, IgxExpansionPanelIconDirective, IgxExpansionPanelBodyComponent, IgxGridComponent, IgxGridToolbarComponent, IgxGridToolbarActionsComponent, IgxGridToolbarPinningComponent, IgxGridToolbarHidingComponent, IgxGridToolbarAdvancedFilteringComponent, IgxGridDetailTemplateDirective, IgxPaginatorComponent, IgxTooltipDirective, IgxColumnGroupComponent, IgxHierarchicalGridComponent, IgxRowIslandComponent, IgxTreeGridComponent, IgxTooltipTargetDirective, IgxIconComponent, IgxSwitchComponent, IgxButtonDirective, IgxCellTemplateDirective } from 'igniteui-angular';
12+
IGridStateOptions, GridFeatures, GridColumnDataType, IgxColumnComponent, GridType, IgxExpansionPanelHeaderComponent, IgxExpansionPanelTitleDirective, IgxExpansionPanelIconDirective, IgxExpansionPanelBodyComponent, IgxGridComponent, IgxGridToolbarComponent, IgxGridToolbarActionsComponent, IgxGridToolbarPinningComponent, IgxGridToolbarHidingComponent, IgxGridToolbarAdvancedFilteringComponent, IgxGridDetailTemplateDirective, IgxPaginatorComponent, IgxTooltipDirective, IgxColumnGroupComponent, IgxHierarchicalGridComponent, IgxRowIslandComponent, IgxTreeGridComponent, IgxTooltipTargetDirective, IgxIconComponent, IgxSwitchComponent, IgxButtonDirective, IgxCellTemplateDirective,
13+
IgxColumnLayoutComponent} from 'igniteui-angular';
1314

1415
class MySummary extends IgxNumberSummaryOperand {
1516

@@ -51,7 +52,7 @@ interface GridState {
5152
styleUrls: ['./grid-state.component.scss'],
5253
templateUrl: './grid-state.component.html',
5354
standalone: true,
54-
imports: [IgxExpansionPanelComponent, IgxCellHeaderTemplateDirective, IgxExpansionPanelHeaderComponent, IgxExpansionPanelTitleDirective, NgIf, IgxExpansionPanelIconDirective, IgxExpansionPanelBodyComponent, NgTemplateOutlet, IgxGridComponent, IgxGridStateDirective, IgxGridToolbarComponent, IgxGridToolbarActionsComponent, IgxGridToolbarPinningComponent, IgxGridToolbarHidingComponent, IgxGridToolbarAdvancedFilteringComponent, NgFor, IgxColumnComponent, IgxGridDetailTemplateDirective, IgxPaginatorComponent, IgxTooltipDirective, IgxColumnGroupComponent, IgxHierarchicalGridComponent, IgxRowIslandComponent, IgxTreeGridComponent, RouterLink, IgxTooltipTargetDirective, IgxIconComponent, IgxSwitchComponent, FormsModule, IgxButtonDirective, IgxCellTemplateDirective]
55+
imports: [IgxColumnLayoutComponent, IgxExpansionPanelComponent, IgxCellHeaderTemplateDirective, IgxExpansionPanelHeaderComponent, IgxExpansionPanelTitleDirective, NgIf, IgxExpansionPanelIconDirective, IgxExpansionPanelBodyComponent, NgTemplateOutlet, IgxGridComponent, IgxGridStateDirective, IgxGridToolbarComponent, IgxGridToolbarActionsComponent, IgxGridToolbarPinningComponent, IgxGridToolbarHidingComponent, IgxGridToolbarAdvancedFilteringComponent, NgFor, IgxColumnComponent, IgxGridDetailTemplateDirective, IgxPaginatorComponent, IgxTooltipDirective, IgxColumnGroupComponent, IgxHierarchicalGridComponent, IgxRowIslandComponent, IgxTreeGridComponent, RouterLink, IgxTooltipTargetDirective, IgxIconComponent, IgxSwitchComponent, FormsModule, IgxButtonDirective, IgxCellTemplateDirective]
5556
})
5657
export class GridSaveStateComponent implements OnInit {
5758
@ViewChild(IgxExpansionPanelComponent, { static: true })
@@ -67,6 +68,7 @@ export class GridSaveStateComponent implements OnInit {
6768
public hGridId = 'hGrid1';
6869
public treeGridId = 'treeGrid1';
6970
public mcGridId = 'mcGrid1';
71+
public mrlGridId = 'mrlGrid1';
7072
public treeGridHierId = 'treeGridH1';
7173
public gridState: IGridState;
7274
public serialize = true;

0 commit comments

Comments
 (0)