diff --git a/projects/igniteui-angular/src/lib/grids/grid-base.component.ts b/projects/igniteui-angular/src/lib/grids/grid-base.component.ts index 6b8c0fa334d..15fa881891d 100644 --- a/projects/igniteui-angular/src/lib/grids/grid-base.component.ts +++ b/projects/igniteui-angular/src/lib/grids/grid-base.component.ts @@ -2288,6 +2288,12 @@ export abstract class IgxGridBaseComponent extends DisplayDensityBase implements this.summaryService.clearSummaryCache(); this._pipeTrigger++; this.markForCheck(); + if (this.transactions.getAggregatedChanges(false).length === 0) { + // Needs better check, calling 'transactions.clear()' will also trigger this + if (this.data.length % this.perPage === 0 && this.isLastPage && this.page !== 0) { + this.page--; + } + } }); } @@ -3075,9 +3081,11 @@ export abstract class IgxGridBaseComponent extends DisplayDensityBase implements this.deleteRowFromData(rowId, index); this._pipeTrigger++; this.cdr.markForCheck(); - + // Data needs to be recalculated if transactions are in place + // If no transactions, `data` will be a reference to the grid getter, otherwise it will be stale + const dataAfterDelete = this.transactions.enabled ? this.dataWithAddedInTransactionRows : data; this.refreshSearch(); - if (data.length % this.perPage === 0 && this.isLastPage && this.page !== 0) { + if (dataAfterDelete.length % this.perPage === 0 && dataAfterDelete.length / this.perPage - 1 < this.page && this.page !== 0) { this.page--; } } diff --git a/projects/igniteui-angular/src/lib/grids/grid/grid.component.spec.ts b/projects/igniteui-angular/src/lib/grids/grid/grid.component.spec.ts index 0de68159bc7..075c6017f93 100644 --- a/projects/igniteui-angular/src/lib/grids/grid/grid.component.spec.ts +++ b/projects/igniteui-angular/src/lib/grids/grid/grid.component.spec.ts @@ -2866,6 +2866,89 @@ describe('IgxGrid Component Tests', () => { expect(targetRowElement.classList).toContain('igx-grid__tr--edited', 'row does not contain edited class w/ edits'); expect(targetCellElement.classList).toContain('igx-grid__td--edited', 'cell does not contain edited class w/ edits'); })); + + it('Should change pages when the only item on the last page is a pending added row that gets deleted', fakeAsync(() => { + const fixture = TestBed.createComponent(IgxGridRowEditingTransactionComponent); + fixture.detectChanges(); + + const grid = fixture.componentInstance.grid; + expect(grid.data.length).toEqual(10); + grid.paging = true; + grid.perPage = 5; + fixture.detectChanges(); + tick(); + expect(grid.totalPages).toEqual(2); + grid.addRow({ + ProductID: 123, + ProductName: 'DummyItem', + InStock: true, + UnitsInStock: 1, + OrderDate: new Date() + }); + fixture.detectChanges(); + tick(); + expect(grid.totalPages).toEqual(3); + grid.page = 2; + tick(); + fixture.detectChanges(); + expect(grid.page).toEqual(2); + grid.deleteRowById(123); + tick(); + fixture.detectChanges(); + // This is behaving incorrectly - if there is only 1 transaction and it is an ADD transaction on the last page + // Deleting the ADD transaction on the last page will trigger grid.page-- TWICE + expect(grid.page).toEqual(1); // Should be 1 + expect(grid.totalPages).toEqual(2); + })); + + it('Should change pages when commiting deletes on the last page', fakeAsync(() => { + const fixture = TestBed.createComponent(IgxGridRowEditingTransactionComponent); + fixture.detectChanges(); + + const grid = fixture.componentInstance.grid; + expect(grid.data.length).toEqual(10); + grid.paging = true; + grid.perPage = 5; + fixture.detectChanges(); + tick(); + expect(grid.totalPages).toEqual(2); + grid.page = 1; + tick(); + fixture.detectChanges(); + expect(grid.page).toEqual(1); + for (let i = 0; i < grid.data.length / 2; i++) { + grid.deleteRowById(grid.data.reverse()[i].ProductID); + } + fixture.detectChanges(); + tick(); + expect(grid.page).toEqual(1); + grid.transactions.commit(grid.data); + fixture.detectChanges(); + tick(); + expect(grid.page).toEqual(0); + expect(grid.totalPages).toEqual(1); + })); + + it('Should NOT change pages when deleting a row on the last page', fakeAsync(() => { + const fixture = TestBed.createComponent(IgxGridRowEditingTransactionComponent); + fixture.detectChanges(); + const grid = fixture.componentInstance.grid; + grid.paging = true; + grid.perPage = 5; + fixture.detectChanges(); + tick(); + expect(grid.totalPages).toEqual(2); + expect(grid.data.length).toEqual(10); + grid.page = 1; + tick(); + fixture.detectChanges(); + expect(grid.page).toEqual(1); + grid.deleteRowById(grid.data[grid.data.length - 1].ProductID); + fixture.detectChanges(); + tick(); + expect(grid.page).toEqual(1); + expect(grid.totalPages).toEqual(2); + })); }); describe('Row Editing - Grouping', () => { diff --git a/projects/igniteui-angular/src/lib/services/transaction/igx-hierarchical-transaction.ts b/projects/igniteui-angular/src/lib/services/transaction/igx-hierarchical-transaction.ts index 786dd331a4d..a79ffaa3d57 100644 --- a/projects/igniteui-angular/src/lib/services/transaction/igx-hierarchical-transaction.ts +++ b/projects/igniteui-angular/src/lib/services/transaction/igx-hierarchical-transaction.ts @@ -2,6 +2,7 @@ import { HierarchicalTransaction, HierarchicalState, TransactionType } from './t import { Injectable } from '@angular/core'; import { IgxTransactionService } from './igx-transaction'; import { DataUtil } from '../../data-operations/data-util'; +import { cloneValue } from '../../core/utils'; /** @experimental @hidden */ @Injectable() @@ -11,7 +12,7 @@ export class IgxHierarchicalTransactionService { - const value = mergeChanges ? this.mergeValues(state.recordRef, state.value) : state.value; + const value = mergeChanges ? this.mergeValues(state.recordRef, state.value) : cloneValue(state.value); this.clearArraysFromObject(value); result.push({ id: key, path: state.path, newValue: value, type: state.type } as T); });