From d70863b267e7e41d8871caa90863d8376a501ce7 Mon Sep 17 00:00:00 2001 From: Miles Malerba Date: Mon, 30 Apr 2018 16:22:28 -0700 Subject: [PATCH] virtual-scroll: fix updating when data changes and add trackBy demos --- .../scrolling/virtual-for-of.ts | 18 +++-- .../virtual-scroll/virtual-scroll-demo.html | 38 +++++++++- .../virtual-scroll/virtual-scroll-demo.scss | 16 +++++ .../virtual-scroll/virtual-scroll-demo.ts | 69 +++++++++++++++++++ 4 files changed, 135 insertions(+), 6 deletions(-) diff --git a/src/cdk-experimental/scrolling/virtual-for-of.ts b/src/cdk-experimental/scrolling/virtual-for-of.ts index a68d67062c76..50cc3b6aec37 100644 --- a/src/cdk-experimental/scrolling/virtual-for-of.ts +++ b/src/cdk-experimental/scrolling/virtual-for-of.ts @@ -147,8 +147,15 @@ export class CdkVirtualForOf implements CollectionViewer, DoCheck, OnDestroy private _differs: IterableDiffers, /** The virtual scrolling viewport that these items are being rendered in. */ @SkipSelf() private _viewport: CdkVirtualScrollViewport) { - this.dataStream.subscribe(data => this._data = data); - this._viewport.renderedRangeStream.subscribe(range => this._onRenderedRangeChange(range)); + this.dataStream.subscribe(data => { + this._data = data; + this._onRenderedDataChange(); + }); + this._viewport.renderedRangeStream.subscribe(range => { + this._renderedRange = range; + this.viewChange.next(this._renderedRange); + this._onRenderedDataChange(); + }); this._viewport.attach(this); } @@ -213,9 +220,10 @@ export class CdkVirtualForOf implements CollectionViewer, DoCheck, OnDestroy } /** React to scroll state changes in the viewport. */ - private _onRenderedRangeChange(renderedRange: ListRange) { - this._renderedRange = renderedRange; - this.viewChange.next(this._renderedRange); + private _onRenderedDataChange() { + if (!this._renderedRange) { + return; + } this._renderedItems = this._data.slice(this._renderedRange.start, this._renderedRange.end); if (!this._differ) { this._differ = this._differs.find(this._renderedItems).create(this.cdkVirtualForTrackBy); diff --git a/src/demo-app/virtual-scroll/virtual-scroll-demo.html b/src/demo-app/virtual-scroll/virtual-scroll-demo.html index fa6e44a0d004..289b8e54a37d 100644 --- a/src/demo-app/virtual-scroll/virtual-scroll-demo.html +++ b/src/demo-app/virtual-scroll/virtual-scroll-demo.html @@ -52,8 +52,44 @@

Fixed size

Observable data

-
Item #{{i}} - ({{size}}px)
+ +

No trackBy

+ + + + +
+
{{state.name}}
+
{{state.capital}}
+
+
+ +

trackBy index

+ + + + +
+
{{state.name}}
+
{{state.capital}}
+
+
+ +

trackBy state name

+ + + + +
+
{{state.name}}
+
{{state.capital}}
+
+
diff --git a/src/demo-app/virtual-scroll/virtual-scroll-demo.scss b/src/demo-app/virtual-scroll/virtual-scroll-demo.scss index 3ce419e652ad..5afdc95ad00e 100644 --- a/src/demo-app/virtual-scroll/virtual-scroll-demo.scss +++ b/src/demo-app/virtual-scroll/virtual-scroll-demo.scss @@ -24,3 +24,19 @@ writing-mode: vertical-lr; } } + +.demo-state-item { + height: 60px; + display: flex; + flex-direction: column; + justify-content: center; +} + +.demo-state { + font-size: 20px; + font-weight: 500; +} + +.demo-capital { + font-size: 14px; +} diff --git a/src/demo-app/virtual-scroll/virtual-scroll-demo.ts b/src/demo-app/virtual-scroll/virtual-scroll-demo.ts index f1e1a6e9335c..7e80c092d9cf 100644 --- a/src/demo-app/virtual-scroll/virtual-scroll-demo.ts +++ b/src/demo-app/virtual-scroll/virtual-scroll-demo.ts @@ -9,6 +9,13 @@ import {Component, ViewEncapsulation} from '@angular/core'; import {BehaviorSubject} from 'rxjs/index'; + +type State = { + name: string, + capital: string +}; + + @Component({ moduleId: module.id, selector: 'virtual-scroll-demo', @@ -23,6 +30,61 @@ export class VirtualScrollDemo { .map((_, i) => (1 + Math.floor((10000 - i) / 1000)) * 20); randomData = Array(10000).fill(0).map(() => Math.round(Math.random() * 100)); observableData = new BehaviorSubject([]); + states = [ + {name: 'Alabama', capital: 'Montgomery'}, + {name: 'Alaska', capital: 'Juneau'}, + {name: 'Arizona', capital: 'Phoenix'}, + {name: 'Arkansas', capital: 'Little Rock'}, + {name: 'California', capital: 'Sacramento'}, + {name: 'Colorado', capital: 'Denver'}, + {name: 'Connecticut', capital: 'Hartford'}, + {name: 'Delaware', capital: 'Dover'}, + {name: 'Florida', capital: 'Tallahassee'}, + {name: 'Georgia', capital: 'Atlanta'}, + {name: 'Hawaii', capital: 'Honolulu'}, + {name: 'Idaho', capital: 'Boise'}, + {name: 'Illinois', capital: 'Springfield'}, + {name: 'Indiana', capital: 'Indianapolis'}, + {name: 'Iowa', capital: 'Des Moines'}, + {name: 'Kansas', capital: 'Topeka'}, + {name: 'Kentucky', capital: 'Frankfort'}, + {name: 'Louisiana', capital: 'Baton Rouge'}, + {name: 'Maine', capital: 'Augusta'}, + {name: 'Maryland', capital: 'Annapolis'}, + {name: 'Massachusetts', capital: 'Boston'}, + {name: 'Michigan', capital: 'Lansing'}, + {name: 'Minnesota', capital: 'St. Paul'}, + {name: 'Mississippi', capital: 'Jackson'}, + {name: 'Missouri', capital: 'Jefferson City'}, + {name: 'Montana', capital: 'Helena'}, + {name: 'Nebraska', capital: 'Lincoln'}, + {name: 'Nevada', capital: 'Carson City'}, + {name: 'New Hampshire', capital: 'Concord'}, + {name: 'New Jersey', capital: 'Trenton'}, + {name: 'New Mexico', capital: 'Santa Fe'}, + {name: 'New York', capital: 'Albany'}, + {name: 'North Carolina', capital: 'Raleigh'}, + {name: 'North Dakota', capital: 'Bismarck'}, + {name: 'Ohio', capital: 'Columbus'}, + {name: 'Oklahoma', capital: 'Oklahoma City'}, + {name: 'Oregon', capital: 'Salem'}, + {name: 'Pennsylvania', capital: 'Harrisburg'}, + {name: 'Rhode Island', capital: 'Providence'}, + {name: 'South Carolina', capital: 'Columbia'}, + {name: 'South Dakota', capital: 'Pierre'}, + {name: 'Tennessee', capital: 'Nashville'}, + {name: 'Texas', capital: 'Austin'}, + {name: 'Utah', capital: 'Salt Lake City'}, + {name: 'Vermont', capital: 'Montpelier'}, + {name: 'Virginia', capital: 'Richmond'}, + {name: 'Washington', capital: 'Olympia'}, + {name: 'West Virginia', capital: 'Charleston'}, + {name: 'Wisconsin', capital: 'Madison'}, + {name: 'Wyoming', capital: 'Cheyenne'}, + ]; + statesObservable = new BehaviorSubject(this.states); + indexTrackFn = (index: number) => index; + nameTrackFn = (_: number, item: State) => item.name; constructor() { this.emitData(); @@ -35,4 +97,11 @@ export class VirtualScrollDemo { setTimeout(() => this.emitData(), 1000); } } + + sortBy(prop: 'name' | 'capital') { + this.statesObservable.next(this.states.map(s => ({...s})).sort((a, b) => { + const aProp = a[prop], bProp = b[prop]; + return aProp < bProp ? -1 : (aProp > bProp ? 1 : 0); + })); + } }