diff --git a/projects/igniteui-angular/directives/src/directives/for-of/for_of.directive.spec.ts b/projects/igniteui-angular/directives/src/directives/for-of/for_of.directive.spec.ts index d6c252db2cb..644b34d24b1 100644 --- a/projects/igniteui-angular/directives/src/directives/for-of/for_of.directive.spec.ts +++ b/projects/igniteui-angular/directives/src/directives/for-of/for_of.directive.spec.ts @@ -586,6 +586,39 @@ describe('IgxForOf directive -', () => { } }); + it('should keep rows in order when the viewport grows at the bottom', async () => { + const component = fix.componentInstance; + component.scrollTop(Number.MAX_SAFE_INTEGER); + fix.detectChanges(); + await wait(); + + component.height = '200px'; + fix.detectChanges(); + await wait(); + + component.height = '600px'; + fix.detectChanges(); + await wait(); + component.scrollTop(Number.MAX_SAFE_INTEGER); + fix.detectChanges(); + await wait(); + + const rows = Array.from(displayContainer.children); + const startIndex = component.data.length - rows.length; + const chunkSize = component.parentVirtDir.state.chunkSize; + if (chunkSize) { + expect(rows.length).toBe(chunkSize); + } + rows.forEach((row, index) => { + const secondCell = row.querySelector(DISPLAY_CONTAINER)?.children[1]; + expect(secondCell?.textContent) + .toBe(component.data[startIndex + index]['1'].toString()); + }); + const lastCell = rows[rows.length - 1].querySelector(DISPLAY_CONTAINER)?.children[1]; + expect(lastCell?.textContent) + .toBe(component.data[component.data.length - 1]['1'].toString()); + }); + it('should scroll to wheel event correctly', async () => { fix.componentInstance.parentVirtDir.dc.instance._scrollInertia.smoothingDuration = 0; /* 120 is default mousewheel on Chrome, scroll 2 records down */ diff --git a/projects/igniteui-angular/directives/src/directives/for-of/for_of.directive.ts b/projects/igniteui-angular/directives/src/directives/for-of/for_of.directive.ts index 8e0b54c9427..7c8a6ca7c46 100644 --- a/projects/igniteui-angular/directives/src/directives/for-of/for_of.directive.ts +++ b/projects/igniteui-angular/directives/src/directives/for-of/for_of.directive.ts @@ -1501,20 +1501,30 @@ export class IgxForOfDirective extends IgxForOfToken= this.igxForOf!.length) { - elemIndex = this.igxForOf!.length - this.state.chunkSize!; + if (!this.isRemote && this.state.startIndex! > 0) { + elemIndex = --this.state.startIndex!; + prepend = true; + } else { + elemIndex = this.igxForOf!.length - this.state.chunkSize!; + } } const input = this.igxForOf![elemIndex]; - const embeddedView = this.dc.instance._vcr.createEmbeddedView( - this._template, - new IgxForOfContext(input, this.igxForOf!, this.getContextIndex(input), this.igxForOf!.length) as any - ); + const context = new IgxForOfContext(input, this.igxForOf!, this.getContextIndex(input), this.igxForOf!.length) as any; + const embeddedView = prepend + ? this.dc.instance._vcr.createEmbeddedView(this._template, context, { index: 0 }) + : this.dc.instance._vcr.createEmbeddedView(this._template, context); - this._embeddedViews.push(embeddedView); + if (prepend) { + this._embeddedViews.unshift(embeddedView); + } else { + this._embeddedViews.push(embeddedView); + } this.state.chunkSize!++; this._zone.run(() => this.cdr.markForCheck()); @@ -1946,20 +1956,30 @@ export class IgxGridForOfDirective extends IgxForOfDirec protected override addLastElem() { let elemIndex = this.state.startIndex! + this.state.chunkSize!; + let prepend = false; if (!this.isRemote && !this.igxForOf) { return; } if (elemIndex >= this.igxForOf!.length) { - elemIndex = this.igxForOf!.length - this.state.chunkSize!; + if (!this.isRemote && this.state.startIndex! > 0) { + elemIndex = --this.state.startIndex!; + prepend = true; + } else { + elemIndex = this.igxForOf!.length - this.state.chunkSize!; + } } const input = this.igxForOf![elemIndex]; - const embeddedView = this.dc.instance._vcr.createEmbeddedView( - this._template, - new IgxGridForOfContext(input, this.igxForOf!, this.getContextIndex(input), this.igxForOf!.length) as any - ); + const context = new IgxGridForOfContext(input, this.igxForOf!, this.getContextIndex(input), this.igxForOf!.length) as any; + const embeddedView = prepend + ? this.dc.instance._vcr.createEmbeddedView(this._template, context, { index: 0 }) + : this.dc.instance._vcr.createEmbeddedView(this._template, context); - this._embeddedViews.push(embeddedView); + if (prepend) { + this._embeddedViews.unshift(embeddedView); + } else { + this._embeddedViews.push(embeddedView); + } this.subscribeToViewObserver(this.getViewObservedNode(embeddedView)); this.state.chunkSize!++; } diff --git a/projects/igniteui-angular/grids/grid/src/grid.component.spec.ts b/projects/igniteui-angular/grids/grid/src/grid.component.spec.ts index 90e47ec2bb6..c66bc4fc3ac 100644 --- a/projects/igniteui-angular/grids/grid/src/grid.component.spec.ts +++ b/projects/igniteui-angular/grids/grid/src/grid.component.spec.ts @@ -156,6 +156,39 @@ describe('IgxGrid Component Tests #grid', () => { expect(grid.columns[1].field).toBe('index'); }); + it('should preserve row ordering when the viewport grows at the bottom', async () => { + const fix = TestBed.createComponent(IgxGridTestComponent); + fix.componentInstance.data = Array.from({ length: 1000 }, (_, index) => ({ index, value: index })); + fix.detectChanges(); + fix.detectChanges(); + + const grid = fix.componentInstance.grid; + const lastIndex = fix.componentInstance.data.length - 1; + + grid.verticalScrollContainer.scrollTo(lastIndex); + await wait(100); + + grid.height = '200px'; + fix.detectChanges(); + await wait(100); + + grid.height = '600px'; + fix.detectChanges(); + await wait(100); + + grid.verticalScrollContainer.scrollTo(lastIndex); + await wait(100); + + const renderedIndexes = grid.rowList.toArray().map(row => row.data.index); + expect(renderedIndexes[renderedIndexes.length - 1]).toBe(lastIndex); + renderedIndexes.forEach((index, position) => { + if (position > 0) { + expect(index).toBe(renderedIndexes[position - 1] + 1); + } + }); + fix.destroy(); + }); + it('should initialize grid with remote virtualization', async () => { const fix = TestBed.createComponent(IgxGridRemoteVirtualizationComponent); fix.detectChanges();