diff --git a/projects/igniteui-angular/src/lib/grids/grid/cell-merge.spec.ts b/projects/igniteui-angular/src/lib/grids/grid/cell-merge.spec.ts index c053bbce81d..a4db6c1c020 100644 --- a/projects/igniteui-angular/src/lib/grids/grid/cell-merge.spec.ts +++ b/projects/igniteui-angular/src/lib/grids/grid/cell-merge.spec.ts @@ -451,8 +451,10 @@ describe('IgxGrid - Cell merging #grid', () => { UIInteractions.simulateClickAndSelectEvent(row1.cells.toArray()[1].nativeElement); await wait(1); + (grid as any)._activeRowIndexes = null; fix.detectChanges(); + expect((grid as any).activeRowIndexes).toEqual([0, 0]); GridFunctions.verifyColumnMergedState(grid, col, [ { value: 'Ignite UI for JavaScript', span: 1 }, { value: 'Ignite UI for JavaScript', span: 1 }, @@ -464,6 +466,212 @@ 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); + (grid as any)._activeRowIndexes = null; + fix.detectChanges(); + + expect((grid as any).activeRowIndexes).toEqual([0, 0]); + 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); + (grid as any)._activeRowIndexes = null; + fix.detectChanges(); + + expect((grid as any).activeRowIndexes).toEqual([1, 1]); + 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); + (grid as any)._activeRowIndexes = null; + fix.detectChanges(); + + expect((grid as any).activeRowIndexes).toEqual([2, 2]); + 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', () => { diff --git a/projects/igniteui-angular/src/lib/grids/grid/grid.pipes.ts b/projects/igniteui-angular/src/lib/grids/grid/grid.pipes.ts index b6c2091ff0b..a35d1959795 100644 --- a/projects/igniteui-angular/src/lib/grids/grid/grid.pipes.ts +++ b/projects/igniteui-angular/src/lib/grids/grid/grid.pipes.ts @@ -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 @@ -129,33 +129,40 @@ 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)) { + // 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(origRecord.cellMergeMeta.entries()) + }; + // 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; } }