|
7 | 7 | */ |
8 | 8 | import {Directive, inject, Input, OnDestroy} from '@angular/core'; |
9 | 9 | 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'; |
12 | 20 | import {CdkVirtualScrollRepeater, CdkVirtualScrollViewport} from '../scrolling'; |
13 | 21 | import { |
14 | 22 | StickyPositioningListener, |
@@ -61,6 +69,16 @@ export class _PositioningListenerProxy implements StickyPositioningListener { |
61 | 69 | export const _TABLE_VIRTUAL_SCROLL_COLLECTION_VIEWER_FACTORY = () => |
62 | 70 | new BehaviorSubject<ListRange>({start: 0, end: 0}); |
63 | 71 |
|
| 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 | + |
64 | 82 | /** |
65 | 83 | * A directive that enables virtual scroll for a {@link CdkTable}. |
66 | 84 | */ |
@@ -148,7 +166,12 @@ export class CdkTableVirtualScroll<T> |
148 | 166 | }); |
149 | 167 |
|
150 | 168 | // 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); |
152 | 175 | this._viewport.attach(this); |
153 | 176 | } |
154 | 177 |
|
|
0 commit comments