From 2ad1677c7370830b67f54fc4191aae98df90646c Mon Sep 17 00:00:00 2001 From: Kristiyan Kostadinov Date: Sat, 18 Jun 2022 15:50:03 +0200 Subject: [PATCH] fix(cdk/scrolling): content jumping in appendOnly mode (#25097) 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. (cherry picked from commit f6bcbb1b04806026c39b2e361b745c0733f8ea20) --- .../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 223cb0802674..329affc0c8dd 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)'); + })); }); }); diff --git a/src/cdk/scrolling/virtual-scroll-viewport.ts b/src/cdk/scrolling/virtual-scroll-viewport.ts index d9181fbf8569..60ee2a4cb7e6 100644 --- a/src/cdk/scrolling/virtual-scroll-viewport.ts +++ b/src/cdk/scrolling/virtual-scroll-viewport.ts @@ -314,6 +314,9 @@ export class CdkVirtualScrollViewport extends CdkScrollable implements OnInit, O * (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'; @@ -321,8 +324,6 @@ export class CdkVirtualScrollViewport extends CdkScrollable implements OnInit, O 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%)`;