import { CollectionViewer , DataSource } from '@angular/cdk/collections' ; import { ChangeDetectionStrategy , Component } from '@angular/core' ; import { BehaviorSubject , Observable , Subscription } from 'rxjs' ; title @ Component ( { selector : 'cdk-virtual-scroll-data-source-example' , styleUrls : [ 'cdk-virtual-scroll-data-source-example.css' ] , templateUrl : 'cdk-virtual-scroll-data-source-example.html' , changeDetection : ChangeDetectionStrategy . OnPush , } ) export class CdkVirtualScrollDataSourceExample { ds = new MyDataSource ( ) ; } export class MyDataSource extends DataSource < string | undefined > { private length = 100000 ; private pageSize = 100 ; private cachedData = Array . from < string > ( { length : this . length } ) ; private fetchedPages = new Set < number > ( ) ; private dataStream = new BehaviorSubject < ( string | undefined ) [ ] > ( this . cachedData ) ; private subscription = new Subscription ( ) ; connect ( collectionViewer ) { this . subscription . add ( collectionViewer . viewChange . subscribe ( range => { const startPage = this . getPageForIndex ( range . start ) ; const endPage = this . getPageForIndex ( range . end - 1 ) ; for ( let i = startPage ; i <= endPage ; i ++ ) { this . fetchPage ( i ) ; } } ) ) ; return this . dataStream ; } disconnect ( ) { this . subscription . unsubscribe ( ) ; } private getPageForIndex ( index ) { return Math . floor ( index / this . pageSize ) ; } private fetchPage ( page ) { if ( this . fetchedPages . has ( page ) ) { return ; } this . fetchedPages . add ( page ) ; setTimeout ( ( ) => { this . cachedData . splice ( page * this . pageSize , this . pageSize , ... Array . from ( { length : this . pageSize } ) . map ( ( _ , i ) => `Item #${ page * this . pageSize + i }` ) ) ; this . dataStream . next ( this . cachedData ) ; } , Math . random ( ) * 1000 + 200 ) ; } }