Skip to content
200 changes: 200 additions & 0 deletions projects/igniteui-angular/src/lib/grids/grid/cell-merge.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -464,6 +464,206 @@ describe('IgxGrid - Cell merging #grid', () => {
]);
});

it('should interrupt merge sequence correctly when there are multiple overlapping merge groups affected.', async () => {
const col1 = grid.getColumnByName('ProductName');
const col2 = grid.getColumnByName('Downloads');
const col3 = grid.getColumnByName('Released');
const col4 = grid.getColumnByName('ReleaseDate');

col1.merge = true;
col2.merge = true;
col3.merge = true;
col4.merge = true;

fix.detectChanges();

const data = [
{
Downloads: 1000,
ID: 1,
ProductName: 'Ignite UI for JavaScript',
ReleaseDate: fix.componentInstance.today,
Released: true
},
{
Downloads: 1000,
ID: 2,
ProductName: 'Ignite UI for JavaScript',
ReleaseDate: fix.componentInstance.today,
Released: true
},
{
Downloads: 1000,
ID: 3,
ProductName: 'Ignite UI for Angular',
ReleaseDate: fix.componentInstance.today,
Released: true
},
{
Downloads: 1000,
ID: 4,
ProductName: 'Ignite UI for JavaScript',
ReleaseDate: fix.componentInstance.prevDay,
Released: true
},
{
Downloads: 100,
ID: 5,
ProductName: 'Ignite UI for Angular',
ReleaseDate: fix.componentInstance.prevDay,
Released: true
},
{
Downloads: 1000,
ID: 6,
ProductName: 'Ignite UI for Angular',
ReleaseDate: null,
Released: true
},
{
Downloads: 0,
ID: 7,
ProductName: null,
ReleaseDate: fix.componentInstance.prevDay,
Released: true
},
{
Downloads: 1000,
ID: 8,
ProductName: 'NetAdvantage',
ReleaseDate: fix.componentInstance.prevDay,
Released: true
},
{
Downloads: 1000,
ID: 9,
ProductName: 'NetAdvantage',
ReleaseDate: null,
Released: true
}
];
fix.componentInstance.data = data;
fix.detectChanges();

const row1 = grid.rowList.toArray()[0];
UIInteractions.simulateClickAndSelectEvent(row1.cells.toArray()[1].nativeElement);
await wait(1);
fix.detectChanges();

GridFunctions.verifyColumnMergedState(grid, col1, [
{ value: 'Ignite UI for JavaScript', span: 1 },
{ value: 'Ignite UI for JavaScript', span: 1 },
{ value: 'Ignite UI for Angular', span: 1 },
{ value: 'Ignite UI for JavaScript', span: 1 },
{ value: 'Ignite UI for Angular', span: 2 },
{ value: null, span: 1 },
{ value: 'NetAdvantage', span: 2 }
]);

GridFunctions.verifyColumnMergedState(grid, col2, [
{ value: 1000, span: 1 },
{ value: 1000, span: 3 },
{ value: 100, span: 1 },
{ value: 1000, span: 1 },
{ value: 0, span: 1 },
{ value: 1000, span: 2 }
]);

GridFunctions.verifyColumnMergedState(grid, col3, [
{ value: true, span: 1 },
{ value: true, span: 8 }
]);

GridFunctions.verifyColumnMergedState(grid, col4, [
{ value: fix.componentInstance.today, span: 1 },
{ value: fix.componentInstance.today, span: 2 },
{ value: fix.componentInstance.prevDay, span: 2 },
{ value: null, span: 1 },
{ value: fix.componentInstance.prevDay, span: 2 },
{ value: null, span: 1 }
]);

const row2 = grid.rowList.toArray()[1];
UIInteractions.simulateClickAndSelectEvent(row2.cells.toArray()[1].nativeElement);
await wait(1);
fix.detectChanges();

GridFunctions.verifyColumnMergedState(grid, col1, [
{ value: 'Ignite UI for JavaScript', span: 1 },
{ value: 'Ignite UI for JavaScript', span: 1 },
{ value: 'Ignite UI for Angular', span: 1 },
{ value: 'Ignite UI for JavaScript', span: 1 },
{ value: 'Ignite UI for Angular', span: 2 },
{ value: null, span: 1 },
{ value: 'NetAdvantage', span: 2 }
]);

GridFunctions.verifyColumnMergedState(grid, col2, [
{ value: 1000, span: 1 },
{ value: 1000, span: 1 },
{ value: 1000, span: 2 },
{ value: 100, span: 1 },
{ value: 1000, span: 1 },
{ value: 0, span: 1 },
{ value: 1000, span: 2 }
]);

GridFunctions.verifyColumnMergedState(grid, col3, [
{ value: true, span: 1 },
{ value: true, span: 1 },
{ value: true, span: 7 }
]);

GridFunctions.verifyColumnMergedState(grid, col4, [
{ value: fix.componentInstance.today, span: 1 },
{ value: fix.componentInstance.today, span: 1 },
{ value: fix.componentInstance.today, span: 1 },
{ value: fix.componentInstance.prevDay, span: 2 },
{ value: null, span: 1 },
{ value: fix.componentInstance.prevDay, span: 2 },
{ value: null, span: 1 }
]);

const row3 = grid.rowList.toArray()[2];
UIInteractions.simulateClickAndSelectEvent(row3.cells.toArray()[1].nativeElement);
await wait(1);
fix.detectChanges();

GridFunctions.verifyColumnMergedState(grid, col1, [
{ value: 'Ignite UI for JavaScript', span: 2 },
{ value: 'Ignite UI for Angular', span: 1 },
{ value: 'Ignite UI for JavaScript', span: 1 },
{ value: 'Ignite UI for Angular', span: 2 },
{ value: null, span: 1 },
{ value: 'NetAdvantage', span: 2 }
]);

GridFunctions.verifyColumnMergedState(grid, col2, [
{ value: 1000, span: 2 },
{ value: 1000, span: 1 },
{ value: 1000, span: 1 },
{ value: 100, span: 1 },
{ value: 1000, span: 1 },
{ value: 0, span: 1 },
{ value: 1000, span: 2 }
]);

GridFunctions.verifyColumnMergedState(grid, col3, [
{ value: true, span: 2 },
{ value: true, span: 1 },
{ value: true, span: 6 }
]);

GridFunctions.verifyColumnMergedState(grid, col4, [
{ value: fix.componentInstance.today, span: 2 },
{ value: fix.componentInstance.today, span: 1 },
{ value: fix.componentInstance.prevDay, span: 2 },
{ value: null, span: 1 },
{ value: fix.componentInstance.prevDay, span: 2 },
{ value: null, span: 1 }
]);
});

});

describe('Updating', () => {
Expand Down
51 changes: 31 additions & 20 deletions projects/igniteui-angular/src/lib/grids/grid/grid.pipes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { FilterUtil, IFilteringStrategy } from '../../data-operations/filtering-
import { ISortingExpression } from '../../data-operations/sorting-strategy';
import { IGridSortingStrategy, IGridGroupingStrategy } from '../common/strategy';
import { GridCellMergeMode, RowPinningPosition } from '../common/enums';
import { IGridMergeStrategy } from '../../data-operations/merge-strategy';
import { IGridMergeStrategy, IMergeByResult } from '../../data-operations/merge-strategy';

/**
* @hidden
Expand Down Expand Up @@ -129,33 +129,44 @@ export class IgxGridUnmergeActivePipe implements PipeTransform {
// if nothing to update, return
return collection;
}

let result = cloneArray(collection) as any;
uniqueRoots.forEach(x => {
const index = result.indexOf(x);
const index = collection.indexOf(x);
const colKeys = [...x.cellMergeMeta.keys()];
const cols = colsToMerge.filter(col => colKeys.indexOf(col.field) !== -1);
let res = [];
for (const col of cols) {

let childData = x.cellMergeMeta.get(col.field).childRecords;
const childData = x.cellMergeMeta.get(col.field).childRecords;
const childRecs = childData.map(rec => rec.recordRef);
const isDate = col?.dataType === 'date' || col?.dataType === 'dateTime';
const isTime = col?.dataType === 'time' || col?.dataType === 'dateTime';
res = this.grid.mergeStrategy.merge(
[x.recordRef, ...childRecs],
col.field,
col.mergingComparer,
res,
activeRowIndexes.map(ri => ri - index),
isDate,
isTime,
this.grid);

if(childRecs.length === 0) {
// nothing to unmerge
continue;
}
const unmergedData = DataUtil.merge([x.recordRef, ...childRecs], [col], this.grid.mergeStrategy, activeRowIndexes.map(ri => ri - index), this.grid);
for (let i = 0; i < unmergedData.length; i++) {
const unmergedRec = unmergedData[i];
const origRecord = result[index + i];
if (unmergedRec.cellMergeMeta?.get(col.field)) {
// deep clone of object, since we don't want to pollute the original fully merged collection.
const objCopy = {
recordRef: origRecord.recordRef,
ghostRecord: origRecord.ghostRecord,
cellMergeMeta: new Map<string, IMergeByResult>()
};
// deep clone of inner map
for (const [key, value] of origRecord.cellMergeMeta) {
objCopy.cellMergeMeta.set(key, structuredClone(value));
}
// update copy with new meta from unmerged data record, but just for this column
objCopy.cellMergeMeta?.set(col.field, unmergedRec.cellMergeMeta.get(col.field));
result[index + i] = objCopy;
} else {
// this is the unmerged record, with no merge metadata
result[index + i] = unmergedRec;
}
}
}
result = result.slice(0, index).concat(res, result.slice(index + res.length));
});


return result;
}
}
Expand Down
Loading