Skip to content

Commit a42b192

Browse files
MKirovaMKirova
authored andcommitted
chore(*): Add mergeStrategy for grid and merging comparer for column.
1 parent 4c5d922 commit a42b192

File tree

9 files changed

+143
-39
lines changed

9 files changed

+143
-39
lines changed

projects/igniteui-angular/src/lib/data-operations/data-util.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { IGroupingState } from './groupby-state.interface';
88
import { mergeObjects } from '../core/utils';
99
import { Transaction, TransactionType, HierarchicalTransaction } from '../services/transaction/transaction';
1010
import { getHierarchy, isHierarchyMatch } from './operations';
11-
import { GridType } from '../grids/common/grid.interface';
11+
import { ColumnType, GridType } from '../grids/common/grid.interface';
1212
import { ITreeGridRecord } from '../grids/tree-grid/tree-grid.interfaces';
1313
import { ISortingExpression } from './sorting-strategy';
1414
import {
@@ -20,6 +20,7 @@ import {
2020
} from '../grids/common/strategy';
2121
import { DefaultDataCloneStrategy, IDataCloneStrategy } from '../data-operations/data-clone-strategy';
2222
import { IGroupingExpression } from './grouping-expression.interface';
23+
import { DefaultMergeStrategy, IGridMergeStrategy } from './merge-strategy';
2324

2425
/**
2526
* @hidden
@@ -37,6 +38,13 @@ import { IGroupingExpression } from './grouping-expression.interface';
3738
} as const;
3839
export type DataType = (typeof DataType)[keyof typeof DataType];
3940

41+
42+
export interface IMergeByResult {
43+
rowSpan: number;
44+
root?: any;
45+
prev?: any;
46+
}
47+
4048
/**
4149
* @hidden
4250
*/
@@ -90,6 +98,15 @@ export class DataUtil {
9098
return grouping.groupBy(data, state, grid, groupsRecords, fullResult);
9199
}
92100

101+
public static merge<T>(data: T[], columns: ColumnType[], strategy: IGridMergeStrategy = new DefaultMergeStrategy(), grid: GridType = null,
102+
): any[] {
103+
let result = [];
104+
for (const col of columns) {
105+
strategy.merge(data, col.field, col.mergingComparer, result);
106+
}
107+
return result;
108+
}
109+
93110
public static page<T>(data: T[], state: IPagingState, dataLength?: number): T[] {
94111
if (!state) {
95112
return data;
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import { GridCellMergeMode, IMergeByResult } from 'igniteui-angular';
2+
import type { KeyOfOrString } from '../core/types';
3+
import { IBaseEventArgs } from '../core/utils';
4+
import { ColumnType, GridType } from '../grids/common/grid.interface';
5+
6+
7+
export interface IGridMergeStrategy {
8+
/* blazorSuppress */
9+
merge: (
10+
data: any[],
11+
field: string,
12+
comparer: (prevRecord: any, currentRecord: any, field: string) => boolean,
13+
result: any[]
14+
) => any[];
15+
}
16+
17+
export class DefaultMergeStrategy implements IGridMergeStrategy {
18+
protected static _instance: DefaultMergeStrategy = null;
19+
20+
public static instance(): DefaultMergeStrategy {
21+
return this._instance || (this._instance = new this());
22+
}
23+
24+
/* blazorSuppress */
25+
public merge(
26+
data: any[],
27+
field: string,
28+
comparer: (prevRecord: any, record: any, field: string) => boolean = this.comparer,
29+
result: any[]
30+
) {
31+
let prev = null;
32+
let index = 0;
33+
for (const rec of data) {
34+
const recData = result[index];
35+
let recToUpdateData = recData ?? { recordRef: rec, cellMergeMeta: new Map<string, IMergeByResult>() };
36+
recToUpdateData.cellMergeMeta.set(field, { rowSpan: 1 });
37+
if (prev && comparer(prev.recordRef, recToUpdateData.recordRef, field)) {
38+
const root = prev.cellMergeMeta.get(field)?.root ?? prev;
39+
root.cellMergeMeta.get(field).rowSpan += 1;
40+
recToUpdateData.cellMergeMeta.get(field).root = root;
41+
}
42+
prev = recToUpdateData;
43+
if (!recData) {
44+
result.push(recToUpdateData);
45+
}
46+
index++;
47+
}
48+
return result;
49+
}
50+
51+
/* blazorSuppress */
52+
public comparer(prevRecord: any, record: any, field: string): boolean {
53+
const a = prevRecord[field];
54+
const b = record[field];
55+
const an = (a === null || a === undefined);
56+
const bn = (b === null || b === undefined);
57+
if (an) {
58+
if (bn) {
59+
return true;
60+
}
61+
return false;
62+
} else if (bn) {
63+
return false;
64+
}
65+
return a === b;
66+
}
67+
}

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

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1209,6 +1209,30 @@ export class IgxColumnComponent implements AfterContentInit, OnDestroy, ColumnTy
12091209
this._sortStrategy = classRef;
12101210
}
12111211

1212+
/* blazorSuppress */
1213+
/**
1214+
* Gets the function that compares values for merging.
1215+
* ```typescript
1216+
* let mergingComparer = this.column.mergingComparer'
1217+
* ```
1218+
*/
1219+
@Input()
1220+
public get mergingComparer(): (prevRecord: any, record: any, field: string) => boolean {
1221+
return this._mergingComparer;
1222+
}
1223+
1224+
/* blazorSuppress */
1225+
/**
1226+
* Sets a custom function to compare values for merging.
1227+
* ```typescript
1228+
* this.column.mergingComparer = (prevRecord: any, record: any, field: string) => { return prevRecord[field] === record[field]; }
1229+
* ```
1230+
*/
1231+
public set mergingComparer(funcRef: (prevRecord: any, record: any, field: string) => boolean) {
1232+
this._mergingComparer = funcRef;
1233+
}
1234+
1235+
12121236
/* blazorSuppress */
12131237
/**
12141238
* Gets the function that compares values for grouping.
@@ -1849,6 +1873,8 @@ export class IgxColumnComponent implements AfterContentInit, OnDestroy, ColumnTy
18491873
* @hidden
18501874
*/
18511875
protected _groupingComparer: (a: any, b: any, currRec?: any, groupRec?: any) => number;
1876+
1877+
protected _mergingComparer: (prevRecord: any, record: any, field: string) => boolean;
18521878
/**
18531879
* @hidden
18541880
*/

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ import { IDimensionsChange, IPivotConfiguration, IPivotDimension, IPivotKeys, IP
3838
import { IDataCloneStrategy } from '../../data-operations/data-clone-strategy';
3939
import { FormControl, FormGroup, ValidationErrors } from '@angular/forms';
4040
import { IgxGridValidationService } from '../grid/grid-validation.service';
41+
import { IGridMergeStrategy } from '../../data-operations/merge-strategy';
4142

4243
export const IGX_GRID_BASE = /*@__PURE__*/new InjectionToken<GridType>('IgxGridBaseToken');
4344
export const IGX_GRID_SERVICE_BASE = /*@__PURE__*/new InjectionToken<GridServiceType>('IgxGridServiceBaseToken');
@@ -335,6 +336,7 @@ export interface ColumnType extends FieldType {
335336
/** @hidden @internal */
336337
headerCell: any;
337338
validators: any[];
339+
mergingComparer: (prevRecord: any, record: any, field: string) => boolean;
338340

339341
/**
340342
* The template reference for the custom header of the column
@@ -692,6 +694,7 @@ export interface GridType extends IGridDataBindable {
692694
/** Represents the locale of the grid: `USD`, `EUR`, `GBP`, `CNY`, `JPY`, etc. */
693695
locale: string;
694696
cellMergeMode: GridCellMergeMode;
697+
mergeStrategy: IGridMergeStrategy;
695698
resourceStrings: IGridResourceStrings;
696699
/* blazorSuppress */
697700
/** Represents the native HTML element itself */

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

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,7 @@ import { IgxGridValidationService } from './grid/grid-validation.service';
185185
import { getCurrentResourceStrings } from '../core/i18n/resources';
186186
import { isTree, recreateTree, recreateTreeFromFields } from '../data-operations/expressions-tree-util';
187187
import { getUUID } from './common/random';
188+
import { IGridMergeStrategy } from '../data-operations/merge-strategy';
188189

189190
interface IMatchInfoCache {
190191
row: any;
@@ -2494,6 +2495,18 @@ export abstract class IgxGridBaseDirective implements GridType,
24942495
this._sortingStrategy = value;
24952496
}
24962497

2498+
2499+
/**
2500+
* Gets/Sets the merge strategy of the grid.
2501+
*
2502+
* @example
2503+
* ```html
2504+
* <igx-grid #grid [data]="localData" [mergeStrategy]="mergeStrategy"></igx-grid>
2505+
* ```
2506+
*/
2507+
@Input()
2508+
public mergeStrategy: IGridMergeStrategy;
2509+
24972510
/**
24982511
* Gets/Sets the sorting options - single or multiple sorting.
24992512
* Accepts an `ISortingOptions` object with any of the `mode` properties.

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

Lines changed: 1 addition & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -95,32 +95,11 @@ export class IgxGridCellMergePipe implements PipeTransform {
9595
if (columnToMerge.length === 0) {
9696
return collection;
9797
}
98-
let prev = null;
99-
let result = [];
100-
for (const rec of collection) {
101-
let recData = { recordRef: rec, cellMergeMeta: new Map<string, IMergeByResult>() };
102-
for (const col of columnToMerge) {
103-
recData.cellMergeMeta.set(col.field, { rowSpan: 1 });
104-
//TODO condition can be a strategy or some callback that the user can set.
105-
if ( prev && prev.recordRef[col.field] === rec[col.field]) {
106-
const root = prev.cellMergeMeta.get(col.field)?.root ?? prev;
107-
root.cellMergeMeta.get(col.field).rowSpan += 1;
108-
recData.cellMergeMeta.get(col.field).root = root;
109-
}
110-
}
111-
prev = recData;
112-
result.push(recData);
113-
}
98+
const result = DataUtil.merge(cloneArray(collection), columnToMerge, this.grid.mergeStrategy, this.grid);
11499
return result;
115100
}
116101
}
117102

118-
export interface IMergeByResult {
119-
rowSpan: number;
120-
root?: any;
121-
prev?: any;
122-
}
123-
124103
/**
125104
* @hidden
126105
*/

projects/igniteui-angular/src/lib/grids/row.directive.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ import { mergeWith } from 'lodash-es';
2727
import { Subject } from 'rxjs';
2828
import { takeUntil } from 'rxjs/operators';
2929
import { trackByIdentity } from '../core/utils';
30-
import { IMergeByResult } from './grid/grid.pipes';
3130

3231
@Directive({
3332
selector: '[igxRowBaseComponent]',

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@ <h4 class="sample-title">Grid with cell merge</h4>
33
<igx-column field="ProductID" header="Product ID" width="200px">
44
<ng-template igxCell let-cell="cell" let-val>
55
<div>
6-
<button igxButton>Test</button>
7-
@if (cell.row.index % 2 == 0) {
6+
<button igxButton>Test {{val}}</button>
7+
<!-- @if (cell.row.index % 2 == 0) {
88
<br/>
99
<button igxButton>Test 2</button>
10-
}
10+
} -->
1111

1212
</div>
1313
</ng-template>

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

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ export class GridCellMergingComponent {
190190
OrderDate2: new Date(1991, 2, 12, 15, 40, 50).toISOString()
191191
},
192192
{
193-
ProductID: 1,
193+
ProductID: 13,
194194
ProductName: 'Chai',
195195
SupplierID: 1,
196196
CategoryID: 1,
@@ -203,7 +203,7 @@ export class GridCellMergingComponent {
203203
OrderDate: null,
204204
OrderDate2: new Date(1991, 2, 12, 18, 40, 50).toISOString()
205205
}, {
206-
ProductID: 2,
206+
ProductID: 14,
207207
ProductName: 'Chai',
208208
SupplierID: 1,
209209
CategoryID: 1,
@@ -217,7 +217,7 @@ export class GridCellMergingComponent {
217217
OrderDate2: new Date('2003-03-17').toISOString()
218218
},
219219
{
220-
ProductID: 3,
220+
ProductID: 15,
221221
ProductName: 'Chai',
222222
SupplierID: 1,
223223
CategoryID: 1,
@@ -231,7 +231,7 @@ export class GridCellMergingComponent {
231231
OrderDate2: new Date('2003-03-17').toISOString()
232232
},
233233
{
234-
ProductID: 4,
234+
ProductID: 16,
235235
ProductName: 'Chai',
236236
SupplierID: 1,
237237
CategoryID: 1,
@@ -245,7 +245,7 @@ export class GridCellMergingComponent {
245245
OrderDate2: new Date('2003-03-17').toISOString()
246246
},
247247
{
248-
ProductID: 5,
248+
ProductID: 17,
249249
ProductName: 'Chai',
250250
SupplierID: 1,
251251
CategoryID: 1,
@@ -259,7 +259,7 @@ export class GridCellMergingComponent {
259259
OrderDate2: new Date('2003-03-17').toISOString()
260260
},
261261
{
262-
ProductID: 6,
262+
ProductID: 18,
263263
ProductName: 'Chang',
264264
SupplierID: 1,
265265
CategoryID: 1,
@@ -273,7 +273,7 @@ export class GridCellMergingComponent {
273273
OrderDate2: new Date('2003-03-17').toISOString()
274274
},
275275
{
276-
ProductID: 7,
276+
ProductID: 19,
277277
ProductName: 'Chang',
278278
SupplierID: 1,
279279
CategoryID: 1,
@@ -287,7 +287,7 @@ export class GridCellMergingComponent {
287287
OrderDate2: new Date('2003-03-17').toISOString()
288288
},
289289
{
290-
ProductID: 8,
290+
ProductID: 20,
291291
ProductName: 'Chang',
292292
SupplierID: 1,
293293
CategoryID: 1,
@@ -301,7 +301,7 @@ export class GridCellMergingComponent {
301301
OrderDate2: new Date('2003-03-17').toISOString()
302302
},
303303
{
304-
ProductID: 9,
304+
ProductID: 21,
305305
ProductName: 'Aniseed Syrup',
306306
SupplierID: 1,
307307
CategoryID: 2,
@@ -315,7 +315,7 @@ export class GridCellMergingComponent {
315315
OrderDate2: new Date(1991, 2, 12, 15, 40, 50).toISOString()
316316
},
317317
{
318-
ProductID: 10,
318+
ProductID: 22,
319319
ProductName: 'Chang',
320320
SupplierID: 1,
321321
CategoryID: 2,
@@ -329,7 +329,7 @@ export class GridCellMergingComponent {
329329
OrderDate2: new Date(1991, 2, 12, 15, 40, 50).toISOString()
330330
},
331331
{
332-
ProductID: 11,
332+
ProductID: 23,
333333
ProductName: 'Chai',
334334
SupplierID: 1,
335335
CategoryID: 2,
@@ -343,7 +343,7 @@ export class GridCellMergingComponent {
343343
OrderDate2: new Date(1991, 2, 12, 15, 40, 50).toISOString()
344344
},
345345
{
346-
ProductID: 12,
346+
ProductID: 24,
347347
ProductName: 'Chai',
348348
SupplierID: 1,
349349
CategoryID: 2,

0 commit comments

Comments
 (0)