From 4ff1c95ae7e7901ac6b954ad4813db8d71aa5224 Mon Sep 17 00:00:00 2001 From: Kristiyan Kostadinov Date: Tue, 5 Mar 2019 16:04:05 +0100 Subject: [PATCH] fix(scrolling): virtual scroll viewport error during server-side rendering (#15299) Fixes the virtual scroll viewport throwing an error during server-side rendering, because it relies on a scheduler that uses `requestAnimationFrame`. Fixes #15291. --- src/cdk/scrolling/virtual-scroll-viewport.ts | 12 ++++++++++-- src/universal-app/kitchen-sink/kitchen-sink.html | 8 ++++++++ src/universal-app/kitchen-sink/kitchen-sink.ts | 6 +++++- 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/src/cdk/scrolling/virtual-scroll-viewport.ts b/src/cdk/scrolling/virtual-scroll-viewport.ts index 2c71c3ddf83..63bdc0a9af6 100644 --- a/src/cdk/scrolling/virtual-scroll-viewport.ts +++ b/src/cdk/scrolling/virtual-scroll-viewport.ts @@ -23,7 +23,7 @@ import { ViewChild, ViewEncapsulation, } from '@angular/core'; -import {animationFrameScheduler, Observable, Subject, Observer} from 'rxjs'; +import {animationFrameScheduler, asapScheduler, Observable, Subject, Observer} from 'rxjs'; import {auditTime, startWith, takeUntil} from 'rxjs/operators'; import {ScrollDispatcher} from './scroll-dispatcher'; import {CdkScrollable, ExtendedScrollToOptions} from './scrollable'; @@ -36,6 +36,14 @@ function rangesEqual(r1: ListRange, r2: ListRange): boolean { return r1.start == r2.start && r1.end == r2.end; } +/** + * Scheduler to be used for scroll events. Needs to fall back to + * something that doesn't rely on requestAnimationFrame on environments + * that don't support it (e.g. server-side rendering). + */ +const SCROLL_SCHEDULER = + typeof requestAnimationFrame !== 'undefined' ? animationFrameScheduler : asapScheduler; + /** A viewport that virtualizes it's scrolling with the help of `CdkVirtualForOf`. */ @Component({ @@ -157,7 +165,7 @@ export class CdkVirtualScrollViewport extends CdkScrollable implements OnInit, O // Collect multiple events into one until the next animation frame. This way if // there are multiple scroll events in the same frame we only need to recheck // our layout once. - auditTime(0, animationFrameScheduler)) + auditTime(0, SCROLL_SCHEDULER)) .subscribe(() => this._scrollStrategy.onContentScrolled()); this._markChangeDetectionNeeded(); diff --git a/src/universal-app/kitchen-sink/kitchen-sink.html b/src/universal-app/kitchen-sink/kitchen-sink.html index bef3a4897b0..b0b3a622b7d 100644 --- a/src/universal-app/kitchen-sink/kitchen-sink.html +++ b/src/universal-app/kitchen-sink/kitchen-sink.html @@ -372,3 +372,11 @@
  • One
  • Two
  • + +

    Virtual scroll

    + + +
    + Item #{{i}} +
    +
    diff --git a/src/universal-app/kitchen-sink/kitchen-sink.ts b/src/universal-app/kitchen-sink/kitchen-sink.ts index 947afe02804..2a862b3f41a 100644 --- a/src/universal-app/kitchen-sink/kitchen-sink.ts +++ b/src/universal-app/kitchen-sink/kitchen-sink.ts @@ -1,4 +1,4 @@ -import {ViewportRuler} from '@angular/cdk/scrolling'; +import {ViewportRuler, ScrollingModule} from '@angular/cdk/scrolling'; import { CdkTableModule, DataSource @@ -77,6 +77,9 @@ export class KitchenSink { /** Data source for the CDK and Material table. */ tableDataSource = new TableDataSource(); + /** Data used to render a virtual scrolling list. */ + virtualScrollData = Array(10000).fill(50); + constructor( snackBar: MatSnackBar, dialog: MatDialog, @@ -135,6 +138,7 @@ export class KitchenSink { MatSortModule, MatTableModule, MatStepperModule, + ScrollingModule, // CDK Modules CdkTableModule,