Skip to content

Commit 4925d8c

Browse files
committed
refactor(cdk/table): resolve virtual scroll rendering issue
Fixes an issue where the table virtual scroller was jumping back to the top whenever it needs to re-render.
1 parent 465674e commit 4925d8c

File tree

1 file changed

+26
-3
lines changed

1 file changed

+26
-3
lines changed

src/cdk/table/table-virtual-scroll.ts

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,16 @@
77
*/
88
import {Directive, inject, Input, OnDestroy} from '@angular/core';
99
import {_RecycleViewRepeaterStrategy, _VIEW_REPEATER_STRATEGY, ListRange} from '../collections';
10-
import {BehaviorSubject, combineLatest, Observable, ReplaySubject, Subject} from 'rxjs';
11-
import {shareReplay, takeUntil} from 'rxjs/operators';
10+
import {
11+
animationFrameScheduler,
12+
asapScheduler,
13+
BehaviorSubject,
14+
combineLatest,
15+
Observable,
16+
ReplaySubject,
17+
Subject,
18+
} from 'rxjs';
19+
import {auditTime, shareReplay, takeUntil} from 'rxjs/operators';
1220
import {CdkVirtualScrollRepeater, CdkVirtualScrollViewport} from '../scrolling';
1321
import {
1422
StickyPositioningListener,
@@ -61,6 +69,16 @@ export class _PositioningListenerProxy implements StickyPositioningListener {
6169
export const _TABLE_VIRTUAL_SCROLL_COLLECTION_VIEWER_FACTORY = () =>
6270
new BehaviorSubject<ListRange>({start: 0, end: 0});
6371

72+
/**
73+
* Scheduler to be used for scroll events. Needs to fall back to
74+
* something that doesn't rely on requestAnimationFrame on environments
75+
* that don't support it (e.g. server-side rendering).
76+
*
77+
* This is identical to the scheduler used by the virtual scroll module.
78+
*/
79+
const SCROLL_SCHEDULER =
80+
typeof requestAnimationFrame !== 'undefined' ? animationFrameScheduler : asapScheduler;
81+
6482
/**
6583
* A directive that enables virtual scroll for a {@link CdkTable}.
6684
*/
@@ -148,7 +166,12 @@ export class CdkTableVirtualScroll<T>
148166
});
149167

150168
// Forward the rendered range computed by the virtual scroll viewport to the table.
151-
this._viewport.renderedRangeStream.pipe(takeUntil(this._destroyed)).subscribe(this._viewChange);
169+
this._viewport.renderedRangeStream
170+
// We need the scheduler here, because the virtual scrolling module uses an identical
171+
// one for scroll listeners. Without it the two go out of sync and the list starts
172+
// jumping back to the beginning whenever it needs to re-render.
173+
.pipe(auditTime(0, SCROLL_SCHEDULER), takeUntil(this._destroyed))
174+
.subscribe(this._viewChange);
152175
this._viewport.attach(this);
153176
}
154177

0 commit comments

Comments
 (0)