Skip to content

Commit 4ff6bfd

Browse files
authored
fix(igxGrid): Fix unmerge when merge groups partially overlap. (#16363)
1 parent 09ec5aa commit 4ff6bfd

File tree

2 files changed

+235
-20
lines changed

2 files changed

+235
-20
lines changed

projects/igniteui-angular/grids/grid/src/cell-merge.spec.ts

Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -454,8 +454,10 @@ describe('IgxGrid - Cell merging #grid', () => {
454454

455455
UIInteractions.simulateClickAndSelectEvent(row1.cells.toArray()[1].nativeElement);
456456
await wait(1);
457+
(grid as any)._activeRowIndexes = null;
457458
fix.detectChanges();
458459

460+
expect((grid as any).activeRowIndexes).toEqual([0, 0]);
459461
GridFunctions.verifyColumnMergedState(grid, col, [
460462
{ value: 'Ignite UI for JavaScript', span: 1 },
461463
{ value: 'Ignite UI for JavaScript', span: 1 },
@@ -467,6 +469,212 @@ describe('IgxGrid - Cell merging #grid', () => {
467469
]);
468470
});
469471

472+
it('should interrupt merge sequence correctly when there are multiple overlapping merge groups affected.', async () => {
473+
const col1 = grid.getColumnByName('ProductName');
474+
const col2 = grid.getColumnByName('Downloads');
475+
const col3 = grid.getColumnByName('Released');
476+
const col4 = grid.getColumnByName('ReleaseDate');
477+
478+
col1.merge = true;
479+
col2.merge = true;
480+
col3.merge = true;
481+
col4.merge = true;
482+
483+
fix.detectChanges();
484+
485+
const data = [
486+
{
487+
Downloads: 1000,
488+
ID: 1,
489+
ProductName: 'Ignite UI for JavaScript',
490+
ReleaseDate: fix.componentInstance.today,
491+
Released: true
492+
},
493+
{
494+
Downloads: 1000,
495+
ID: 2,
496+
ProductName: 'Ignite UI for JavaScript',
497+
ReleaseDate: fix.componentInstance.today,
498+
Released: true
499+
},
500+
{
501+
Downloads: 1000,
502+
ID: 3,
503+
ProductName: 'Ignite UI for Angular',
504+
ReleaseDate: fix.componentInstance.today,
505+
Released: true
506+
},
507+
{
508+
Downloads: 1000,
509+
ID: 4,
510+
ProductName: 'Ignite UI for JavaScript',
511+
ReleaseDate: fix.componentInstance.prevDay,
512+
Released: true
513+
},
514+
{
515+
Downloads: 100,
516+
ID: 5,
517+
ProductName: 'Ignite UI for Angular',
518+
ReleaseDate: fix.componentInstance.prevDay,
519+
Released: true
520+
},
521+
{
522+
Downloads: 1000,
523+
ID: 6,
524+
ProductName: 'Ignite UI for Angular',
525+
ReleaseDate: null,
526+
Released: true
527+
},
528+
{
529+
Downloads: 0,
530+
ID: 7,
531+
ProductName: null,
532+
ReleaseDate: fix.componentInstance.prevDay,
533+
Released: true
534+
},
535+
{
536+
Downloads: 1000,
537+
ID: 8,
538+
ProductName: 'NetAdvantage',
539+
ReleaseDate: fix.componentInstance.prevDay,
540+
Released: true
541+
},
542+
{
543+
Downloads: 1000,
544+
ID: 9,
545+
ProductName: 'NetAdvantage',
546+
ReleaseDate: null,
547+
Released: true
548+
}
549+
];
550+
fix.componentInstance.data = data;
551+
fix.detectChanges();
552+
553+
const row1 = grid.rowList.toArray()[0];
554+
UIInteractions.simulateClickAndSelectEvent(row1.cells.toArray()[1].nativeElement);
555+
await wait(1);
556+
(grid as any)._activeRowIndexes = null;
557+
fix.detectChanges();
558+
559+
expect((grid as any).activeRowIndexes).toEqual([0, 0]);
560+
GridFunctions.verifyColumnMergedState(grid, col1, [
561+
{ value: 'Ignite UI for JavaScript', span: 1 },
562+
{ value: 'Ignite UI for JavaScript', span: 1 },
563+
{ value: 'Ignite UI for Angular', span: 1 },
564+
{ value: 'Ignite UI for JavaScript', span: 1 },
565+
{ value: 'Ignite UI for Angular', span: 2 },
566+
{ value: null, span: 1 },
567+
{ value: 'NetAdvantage', span: 2 }
568+
]);
569+
570+
GridFunctions.verifyColumnMergedState(grid, col2, [
571+
{ value: 1000, span: 1 },
572+
{ value: 1000, span: 3 },
573+
{ value: 100, span: 1 },
574+
{ value: 1000, span: 1 },
575+
{ value: 0, span: 1 },
576+
{ value: 1000, span: 2 }
577+
]);
578+
579+
GridFunctions.verifyColumnMergedState(grid, col3, [
580+
{ value: true, span: 1 },
581+
{ value: true, span: 8 }
582+
]);
583+
584+
GridFunctions.verifyColumnMergedState(grid, col4, [
585+
{ value: fix.componentInstance.today, span: 1 },
586+
{ value: fix.componentInstance.today, span: 2 },
587+
{ value: fix.componentInstance.prevDay, span: 2 },
588+
{ value: null, span: 1 },
589+
{ value: fix.componentInstance.prevDay, span: 2 },
590+
{ value: null, span: 1 }
591+
]);
592+
593+
const row2 = grid.rowList.toArray()[1];
594+
UIInteractions.simulateClickAndSelectEvent(row2.cells.toArray()[1].nativeElement);
595+
await wait(1);
596+
(grid as any)._activeRowIndexes = null;
597+
fix.detectChanges();
598+
599+
expect((grid as any).activeRowIndexes).toEqual([1, 1]);
600+
GridFunctions.verifyColumnMergedState(grid, col1, [
601+
{ value: 'Ignite UI for JavaScript', span: 1 },
602+
{ value: 'Ignite UI for JavaScript', span: 1 },
603+
{ value: 'Ignite UI for Angular', span: 1 },
604+
{ value: 'Ignite UI for JavaScript', span: 1 },
605+
{ value: 'Ignite UI for Angular', span: 2 },
606+
{ value: null, span: 1 },
607+
{ value: 'NetAdvantage', span: 2 }
608+
]);
609+
610+
GridFunctions.verifyColumnMergedState(grid, col2, [
611+
{ value: 1000, span: 1 },
612+
{ value: 1000, span: 1 },
613+
{ value: 1000, span: 2 },
614+
{ value: 100, span: 1 },
615+
{ value: 1000, span: 1 },
616+
{ value: 0, span: 1 },
617+
{ value: 1000, span: 2 }
618+
]);
619+
620+
GridFunctions.verifyColumnMergedState(grid, col3, [
621+
{ value: true, span: 1 },
622+
{ value: true, span: 1 },
623+
{ value: true, span: 7 }
624+
]);
625+
626+
GridFunctions.verifyColumnMergedState(grid, col4, [
627+
{ value: fix.componentInstance.today, span: 1 },
628+
{ value: fix.componentInstance.today, span: 1 },
629+
{ value: fix.componentInstance.today, span: 1 },
630+
{ value: fix.componentInstance.prevDay, span: 2 },
631+
{ value: null, span: 1 },
632+
{ value: fix.componentInstance.prevDay, span: 2 },
633+
{ value: null, span: 1 }
634+
]);
635+
636+
const row3 = grid.rowList.toArray()[2];
637+
UIInteractions.simulateClickAndSelectEvent(row3.cells.toArray()[1].nativeElement);
638+
await wait(1);
639+
(grid as any)._activeRowIndexes = null;
640+
fix.detectChanges();
641+
642+
expect((grid as any).activeRowIndexes).toEqual([2, 2]);
643+
GridFunctions.verifyColumnMergedState(grid, col1, [
644+
{ value: 'Ignite UI for JavaScript', span: 2 },
645+
{ value: 'Ignite UI for Angular', span: 1 },
646+
{ value: 'Ignite UI for JavaScript', span: 1 },
647+
{ value: 'Ignite UI for Angular', span: 2 },
648+
{ value: null, span: 1 },
649+
{ value: 'NetAdvantage', span: 2 }
650+
]);
651+
652+
GridFunctions.verifyColumnMergedState(grid, col2, [
653+
{ value: 1000, span: 2 },
654+
{ value: 1000, span: 1 },
655+
{ value: 1000, span: 1 },
656+
{ value: 100, span: 1 },
657+
{ value: 1000, span: 1 },
658+
{ value: 0, span: 1 },
659+
{ value: 1000, span: 2 }
660+
]);
661+
662+
GridFunctions.verifyColumnMergedState(grid, col3, [
663+
{ value: true, span: 2 },
664+
{ value: true, span: 1 },
665+
{ value: true, span: 6 }
666+
]);
667+
668+
GridFunctions.verifyColumnMergedState(grid, col4, [
669+
{ value: fix.componentInstance.today, span: 2 },
670+
{ value: fix.componentInstance.today, span: 1 },
671+
{ value: fix.componentInstance.prevDay, span: 2 },
672+
{ value: null, span: 1 },
673+
{ value: fix.componentInstance.prevDay, span: 2 },
674+
{ value: null, span: 1 }
675+
]);
676+
});
677+
470678
});
471679

472680
describe('Updating', () => {

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

Lines changed: 27 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { Inject, Pipe, PipeTransform } from '@angular/core';
2-
import { IGridSortingStrategy, IGridGroupingStrategy, cloneArray, DataUtil, FilteringExpressionsTree, FilterUtil, IFilteringExpressionsTree, IFilteringStrategy, IGridMergeStrategy, IGroupByExpandState, IGroupingExpression, ISortingExpression, IGroupByResult, ColumnType } from 'igniteui-angular/core';
2+
import { IGridSortingStrategy, IGridGroupingStrategy, cloneArray, DataUtil, FilteringExpressionsTree, FilterUtil, IFilteringExpressionsTree, IFilteringStrategy, IGridMergeStrategy, IGroupByExpandState, IGroupingExpression, ISortingExpression, IGroupByResult, ColumnType, IMergeByResult } from 'igniteui-angular/core';
33
import { GridCellMergeMode, RowPinningPosition, GridType, IGX_GRID_BASE } from 'igniteui-angular/grids/core';
44

55
/**
@@ -119,33 +119,40 @@ export class IgxGridUnmergeActivePipe implements PipeTransform {
119119
// if nothing to update, return
120120
return collection;
121121
}
122+
122123
let result = cloneArray(collection) as any;
123124
uniqueRoots.forEach(x => {
124-
const index = result.indexOf(x);
125+
const index = collection.indexOf(x);
125126
const colKeys = [...x.cellMergeMeta.keys()];
126127
const cols = colsToMerge.filter(col => colKeys.indexOf(col.field) !== -1);
127-
let res = [];
128128
for (const col of cols) {
129-
130-
let childData = x.cellMergeMeta.get(col.field).childRecords;
129+
const childData = x.cellMergeMeta.get(col.field).childRecords;
131130
const childRecs = childData.map(rec => rec.recordRef);
132-
const isDate = col?.dataType === 'date' || col?.dataType === 'dateTime';
133-
const isTime = col?.dataType === 'time' || col?.dataType === 'dateTime';
134-
res = this.grid.mergeStrategy.merge(
135-
[x.recordRef, ...childRecs],
136-
col.field,
137-
col.mergingComparer,
138-
res,
139-
activeRowIndexes.map(ri => ri - index),
140-
isDate,
141-
isTime,
142-
this.grid);
143-
131+
if(childRecs.length === 0) {
132+
// nothing to unmerge
133+
continue;
134+
}
135+
const unmergedData = DataUtil.merge([x.recordRef, ...childRecs], [col], this.grid.mergeStrategy, activeRowIndexes.map(ri => ri - index), this.grid);
136+
for (let i = 0; i < unmergedData.length; i++) {
137+
const unmergedRec = unmergedData[i];
138+
const origRecord = result[index + i];
139+
if (unmergedRec.cellMergeMeta?.get(col.field)) {
140+
// clone of object, since we don't want to pollute the original fully merged collection.
141+
const objCopy = {
142+
recordRef: origRecord.recordRef,
143+
ghostRecord: origRecord.ghostRecord,
144+
cellMergeMeta: new Map<string, IMergeByResult>(origRecord.cellMergeMeta.entries())
145+
};
146+
// update copy with new meta from unmerged data record, but just for this column
147+
objCopy.cellMergeMeta?.set(col.field, unmergedRec.cellMergeMeta.get(col.field));
148+
result[index + i] = objCopy;
149+
} else {
150+
// this is the unmerged record, with no merge metadata
151+
result[index + i] = unmergedRec;
152+
}
153+
}
144154
}
145-
result = result.slice(0, index).concat(res, result.slice(index + res.length));
146155
});
147-
148-
149156
return result;
150157
}
151158
}

0 commit comments

Comments
 (0)