Skip to content

Commit d061339

Browse files
committed
virtual-scroll: simplify viewport change detection
1 parent 57576eb commit d061339

File tree

1 file changed

+18
-59
lines changed

1 file changed

+18
-59
lines changed

src/cdk-experimental/scrolling/virtual-scroll-viewport.ts

Lines changed: 18 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -11,24 +11,30 @@ import {
1111
ChangeDetectionStrategy,
1212
ChangeDetectorRef,
1313
Component,
14-
DoCheck,
1514
ElementRef,
1615
Inject,
1716
Input,
18-
NgZone,
1917
OnDestroy,
2018
OnInit,
2119
ViewChild,
2220
ViewEncapsulation,
2321
} from '@angular/core';
2422
import {Observable} from 'rxjs/Observable';
2523
import {fromEvent} from 'rxjs/observable/fromEvent';
24+
import {throttleTime} from 'rxjs/operators';
2625
import {takeUntil} from 'rxjs/operators/takeUntil';
26+
import {animationFrame} from 'rxjs/scheduler/animationFrame';
2727
import {Subject} from 'rxjs/Subject';
2828
import {CdkVirtualForOf} from './virtual-for-of';
2929
import {VIRTUAL_SCROLL_STRATEGY, VirtualScrollStrategy} from './virtual-scroll-strategy';
3030

3131

32+
/** Checks if the given ranges are equal. */
33+
function rangesEqual(r1: Range, r2: Range): boolean {
34+
return r1.start == r2.start && r1.end == r2.end;
35+
}
36+
37+
3238
/** A viewport that virtualizes it's scrolling with the help of `CdkVirtualForOf`. */
3339
@Component({
3440
moduleId: module.id,
@@ -42,7 +48,7 @@ import {VIRTUAL_SCROLL_STRATEGY, VirtualScrollStrategy} from './virtual-scroll-s
4248
changeDetection: ChangeDetectionStrategy.OnPush,
4349
preserveWhitespaces: false,
4450
})
45-
export class CdkVirtualScrollViewport implements OnInit, DoCheck, OnDestroy {
51+
export class CdkVirtualScrollViewport implements OnInit, OnDestroy {
4652
/** Emits when the viewport is detached from a CdkVirtualForOf. */
4753
private _detachedSubject = new Subject<void>();
4854

@@ -78,16 +84,7 @@ export class CdkVirtualScrollViewport implements OnInit, DoCheck, OnDestroy {
7884
/** Whether this viewport is attached to a CdkVirtualForOf. */
7985
private _isAttached = false;
8086

81-
/**
82-
* The scroll handling status.
83-
* needed - The scroll state needs to be updated, but a check hasn't yet been scheduled.
84-
* pending - The scroll state needs to be updated, and an update has already been scheduled.
85-
* done - The scroll state does not need to be updated.
86-
*/
87-
private _scrollHandledStatus: 'needed' | 'pending' | 'done' = 'done';
88-
8987
constructor(public elementRef: ElementRef, private _changeDetectorRef: ChangeDetectorRef,
90-
private _ngZone: NgZone,
9188
@Inject(VIRTUAL_SCROLL_STRATEGY) private _scrollStrategy: VirtualScrollStrategy) {}
9289

9390
/** Gets the length of the data bound to this viewport (in number of items). */
@@ -108,22 +105,16 @@ export class CdkVirtualScrollViewport implements OnInit, DoCheck, OnDestroy {
108105
*/
109106
setTotalContentSize(size: number) {
110107
if (this._totalContentSize != size) {
111-
// Re-enter the Angular zone so we can mark for change detection.
112-
this._ngZone.run(() => {
113-
this._totalContentSize = size;
114-
this._changeDetectorRef.markForCheck();
115-
});
108+
this._totalContentSize = size;
109+
this._changeDetectorRef.markForCheck();
116110
}
117111
}
118112

119113
/** Sets the currently rendered range of indices. */
120114
setRenderedRange(range: Range) {
121-
if (!this._rangesEqual(this._renderedRange, range)) {
122-
// Re-enter the Angular zone so we can mark for change detection.
123-
this._ngZone.run(() => {
124-
this._renderedRangeSubject.next(this._renderedRange = range);
125-
this._changeDetectorRef.markForCheck();
126-
});
115+
if (!rangesEqual(this._renderedRange, range)) {
116+
this._renderedRangeSubject.next(this._renderedRange = range);
117+
this._changeDetectorRef.markForCheck();
127118
}
128119
}
129120

@@ -132,11 +123,8 @@ export class CdkVirtualScrollViewport implements OnInit, DoCheck, OnDestroy {
132123
const transform =
133124
this.orientation === 'horizontal' ? `translateX(${offset}px)` : `translateY(${offset}px)`;
134125
if (this._renderedContentTransform != transform) {
135-
// Re-enter the Angular zone so we can mark for change detection.
136-
this._ngZone.run(() => {
137-
this._renderedContentTransform = transform;
138-
this._changeDetectorRef.markForCheck();
139-
});
126+
this._renderedContentTransform = transform;
127+
this._changeDetectorRef.markForCheck();
140128
}
141129
}
142130

@@ -174,25 +162,12 @@ export class CdkVirtualScrollViewport implements OnInit, DoCheck, OnDestroy {
174162
Promise.resolve().then(() => {
175163
this._viewportSize = this.orientation === 'horizontal' ?
176164
this.elementRef.nativeElement.clientWidth : this.elementRef.nativeElement.clientHeight;
177-
this._ngZone.runOutsideAngular(() => {
178-
fromEvent(this.elementRef.nativeElement, 'scroll').subscribe(() => {
179-
this._markScrolled();
180-
});
181-
});
165+
fromEvent(this.elementRef.nativeElement, 'scroll').pipe(throttleTime(0, animationFrame))
166+
.subscribe(() => this._scrollStrategy.onContentScrolled());
182167
this._scrollStrategy.attach(this);
183168
});
184169
}
185170

186-
ngDoCheck() {
187-
if (this._scrollHandledStatus === 'needed') {
188-
this._scrollHandledStatus = 'pending';
189-
this._ngZone.runOutsideAngular(() => requestAnimationFrame(() => {
190-
this._scrollHandledStatus = 'done';
191-
this._scrollStrategy.onContentScrolled();
192-
}));
193-
}
194-
}
195-
196171
ngOnDestroy() {
197172
this.detach();
198173
this._scrollStrategy.detach();
@@ -201,20 +176,4 @@ export class CdkVirtualScrollViewport implements OnInit, DoCheck, OnDestroy {
201176
this._detachedSubject.complete();
202177
this._renderedRangeSubject.complete();
203178
}
204-
205-
/** Marks that a scroll event happened and that the scroll state should be checked. */
206-
private _markScrolled() {
207-
if (this._scrollHandledStatus === 'done') {
208-
// Re-enter the Angular zone so we can mark for change detection.
209-
this._ngZone.run(() => {
210-
this._scrollHandledStatus = 'needed';
211-
this._changeDetectorRef.markForCheck();
212-
});
213-
}
214-
}
215-
216-
/** Checks if the given ranges are equal. */
217-
private _rangesEqual(r1: Range, r2: Range): boolean {
218-
return r1.start == r2.start && r1.end == r2.end;
219-
}
220179
}

0 commit comments

Comments
 (0)