Skip to content

Commit 9953c57

Browse files
authored
Merge branch 'master' into ganastasov/fix-14262-master
2 parents 7895648 + 1ddfd26 commit 9953c57

File tree

8 files changed

+167
-14
lines changed

8 files changed

+167
-14
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/grid-base.directive.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -989,6 +989,11 @@ export abstract class IgxGridBaseDirective implements GridType,
989989
@Output()
990990
public expansionStatesChange = new EventEmitter<Map<any, boolean>>();
991991

992+
/* blazorInclude */
993+
/** @hidden @internal */
994+
@Output()
995+
public selectedRowsChange = new EventEmitter<any[]>();
996+
992997
/**
993998
* Emitted when the expanded state of a row gets changed.
994999
*
@@ -2458,7 +2463,7 @@ export abstract class IgxGridBaseDirective implements GridType,
24582463

24592464
/* blazorByValueArray */
24602465
/* blazorAlwaysWriteback */
2461-
/* @tsTwoWayProperty (true, "RowSelectionChanging", "Detail.NewSelection", false) */
2466+
/* @tsTwoWayProperty (true, "SelectedRowsChange", "Detail", false) */
24622467
/* blazorPrimitiveValue */
24632468
/**
24642469
* Gets/Sets the current selection state.
@@ -3412,6 +3417,9 @@ export abstract class IgxGridBaseDirective implements GridType,
34123417
this._transactions = this.transactionFactory.create(TRANSACTION_TYPE.None);
34133418
this._transactions.cloneStrategy = this.dataCloneStrategy;
34143419
this.cdr.detach();
3420+
this.selectionService.selectedRowsChange.pipe(takeUntil(this.destroy$)).subscribe((args: any[]) => {
3421+
this.selectedRowsChange.emit(args);
3422+
});
34153423
IgcTrialWatermark.register();
34163424
}
34173425

projects/igniteui-angular/src/lib/grids/selection/selection.service.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ export class IgxGridSelectionService {
3333
/**
3434
* @hidden @internal
3535
*/
36-
public selectedRowsChange = new Subject<void>();
36+
public selectedRowsChange = new Subject<any[]>();
3737

3838
/**
3939
* Toggled when a pointerdown event is triggered inside the grid body (cells).
@@ -561,14 +561,14 @@ export class IgxGridSelectionService {
561561
}
562562
rowIDs.forEach(rowID => this.rowSelection.add(rowID));
563563
this.clearHeaderCBState();
564-
this.selectedRowsChange.next();
564+
this.selectedRowsChange.next(rowIDs);
565565
}
566566

567567
/** Deselect specified rows. No event is emitted. */
568568
public deselectRowsWithNoEvent(rowIDs: any[]): void {
569569
this.clearHeaderCBState();
570570
rowIDs.forEach(rowID => this.rowSelection.delete(rowID));
571-
this.selectedRowsChange.next();
571+
this.selectedRowsChange.next(this.getSelectedRows());
572572
}
573573

574574
public isRowSelected(rowID): boolean {
@@ -689,7 +689,7 @@ export class IgxGridSelectionService {
689689
this.rowSelection.clear();
690690
this.indeterminateRows.clear();
691691
this.clearHeaderCBState();
692-
this.selectedRowsChange.next();
692+
this.selectedRowsChange.next([]);
693693
}
694694

695695
/** Returns all data in the grid, with applied filtering and sorting and without deleted rows. */

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

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ export class IgxTreeGridSelectionService extends IgxGridSelectionService {
5858
this.indeterminateRows = new Set(this.rowsToBeIndeterminate);
5959
// TODO: emit selectionChangeD event, calculate its args through the handleAddedAndRemovedArgs method
6060
this.clearHeaderCBState();
61-
this.selectedRowsChange.next();
61+
this.selectedRowsChange.next(this.getSelectedRows());
6262
return;
6363
}
6464
const newParents = new Set<any>();
@@ -89,7 +89,7 @@ export class IgxTreeGridSelectionService extends IgxGridSelectionService {
8989
this.rowSelection = new Set(this.rowsToBeSelected);
9090
this.indeterminateRows = new Set(this.rowsToBeIndeterminate);
9191
this.clearHeaderCBState();
92-
this.selectedRowsChange.next();
92+
this.selectedRowsChange.next(this.getSelectedRows());
9393
}
9494

9595
private cascadeDeselectRowsWithNoEvent(rowIDs: any[]): void {
@@ -99,7 +99,7 @@ export class IgxTreeGridSelectionService extends IgxGridSelectionService {
9999
this.rowSelection = new Set(this.rowsToBeSelected);
100100
this.indeterminateRows = new Set(this.rowsToBeIndeterminate);
101101
this.clearHeaderCBState();
102-
this.selectedRowsChange.next();
102+
this.selectedRowsChange.next(this.getSelectedRows());
103103
}
104104

105105
public get selectionService(): IgxGridSelectionService {
@@ -134,7 +134,7 @@ export class IgxTreeGridSelectionService extends IgxGridSelectionService {
134134
this.rowSelection = new Set(this.rowsToBeSelected);
135135
this.indeterminateRows = new Set(this.rowsToBeIndeterminate);
136136
this.clearHeaderCBState();
137-
this.selectedRowsChange.next();
137+
this.selectedRowsChange.next(this.getSelectedRows());
138138
} else {
139139
// select the rows within the modified args.newSelection with no event
140140
this.cascadeSelectRowsWithNoEvent(newSelectionIDs, true);

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)