From dc08edc86c9eb98b163df5fda1e8038841782dbb Mon Sep 17 00:00:00 2001 From: Kristiyan Kostadinov Date: Fri, 17 Jun 2022 09:01:14 +0200 Subject: [PATCH] fix(cdk/scrolling): content jumping in appendOnly mode We were creating the `transform` string before adjusting the offset for `appendOnly` mode which was causing the list to jump down before being reset on the next scroll event. These changes resolve the issue by moving the offset adjustment up to before the `transform`. Fixes #25077. --- .../scrolling/virtual-scroll-viewport.spec.ts | 19 +++++++++++++++++++ src/cdk/scrolling/virtual-scroll-viewport.ts | 5 +++-- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/cdk/scrolling/virtual-scroll-viewport.spec.ts b/src/cdk/scrolling/virtual-scroll-viewport.spec.ts index 44366f6f51c4..e307679eda57 100644 --- a/src/cdk/scrolling/virtual-scroll-viewport.spec.ts +++ b/src/cdk/scrolling/virtual-scroll-viewport.spec.ts @@ -1030,6 +1030,7 @@ describe('CdkVirtualScrollViewport', () => { let fixture: ComponentFixture; let testComponent: VirtualScrollWithAppendOnly; let viewport: CdkVirtualScrollViewport; + let contentWrapperEl: HTMLElement; beforeEach(waitForAsync(() => { TestBed.configureTestingModule({ @@ -1039,6 +1040,9 @@ describe('CdkVirtualScrollViewport', () => { fixture = TestBed.createComponent(VirtualScrollWithAppendOnly); testComponent = fixture.componentInstance; viewport = testComponent.viewport; + contentWrapperEl = fixture.nativeElement.querySelector( + '.cdk-virtual-scroll-content-wrapper', + ) as HTMLElement; })); it('should not remove item that have already been rendered', fakeAsync(() => { @@ -1085,6 +1089,21 @@ describe('CdkVirtualScrollViewport', () => { expect(viewport.getOffsetToRenderedContentStart()).toBe(0); })); + + it('should not set a transform when scrolling', fakeAsync(() => { + finishInit(fixture); + triggerScroll(viewport, 0); + fixture.detectChanges(); + flush(); + + expect(contentWrapperEl.style.transform).toBe('translateY(0px)'); + + triggerScroll(viewport, testComponent.itemSize * 10); + fixture.detectChanges(); + flush(); + + expect(contentWrapperEl.style.transform).toBe('translateY(0px)'); + })); }); describe('with custom scrolling element', () => { diff --git a/src/cdk/scrolling/virtual-scroll-viewport.ts b/src/cdk/scrolling/virtual-scroll-viewport.ts index 0f5257a25a1e..77253c5db6ce 100644 --- a/src/cdk/scrolling/virtual-scroll-viewport.ts +++ b/src/cdk/scrolling/virtual-scroll-viewport.ts @@ -333,6 +333,9 @@ export class CdkVirtualScrollViewport extends CdkVirtualScrollable implements On * (in pixels). */ setRenderedContentOffset(offset: number, to: 'to-start' | 'to-end' = 'to-start') { + // In appendOnly, we always start from the top + offset = this.appendOnly && to === 'to-start' ? 0 : offset; + // For a horizontal viewport in a right-to-left language we need to translate along the x-axis // in the negative direction. const isRtl = this.dir && this.dir.value == 'rtl'; @@ -340,8 +343,6 @@ export class CdkVirtualScrollViewport extends CdkVirtualScrollable implements On const axis = isHorizontal ? 'X' : 'Y'; const axisDirection = isHorizontal && isRtl ? -1 : 1; let transform = `translate${axis}(${Number(axisDirection * offset)}px)`; - // in appendOnly, we always start from the top - offset = this.appendOnly && to === 'to-start' ? 0 : offset; this._renderedContentOffset = offset; if (to === 'to-end') { transform += ` translate${axis}(-100%)`;