Skip to content

Commit c36466c

Browse files
crisbetommalerba
authored andcommitted
fix(scrolling): update virtual scroll viewport size on resize (#18058)
We currently cache the size of the virtual scroll viewport, but it may become inaccurate if it's a percentage of the page viewport and the page is resized. These changes add an extra call that'll update the virtual scroll viewport on resize. Fixes #16802.
1 parent 99af8e9 commit c36466c

File tree

3 files changed

+48
-5
lines changed

3 files changed

+48
-5
lines changed

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

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,15 @@ import {
1616
Directive,
1717
ViewContainerRef
1818
} from '@angular/core';
19-
import {async, ComponentFixture, fakeAsync, flush, inject, TestBed} from '@angular/core/testing';
19+
import {
20+
async,
21+
ComponentFixture,
22+
fakeAsync,
23+
flush,
24+
inject,
25+
TestBed,
26+
tick,
27+
} from '@angular/core/testing';
2028
import {animationFrameScheduler, Subject} from 'rxjs';
2129

2230

@@ -74,6 +82,17 @@ describe('CdkVirtualScrollViewport', () => {
7482
expect(viewport.getViewportSize()).toBe(500);
7583
}));
7684

85+
it('should update the viewport size when the page viewport changes', fakeAsync(() => {
86+
finishInit(fixture);
87+
spyOn(viewport, 'checkViewportSize').and.callThrough();
88+
89+
dispatchFakeEvent(window, 'resize');
90+
fixture.detectChanges();
91+
tick(20); // The resize listener is debounced so we need to flush it.
92+
93+
expect(viewport.checkViewportSize).toHaveBeenCalled();
94+
}));
95+
7796
it('should get the rendered range', fakeAsync(() => {
7897
finishInit(fixture);
7998

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

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,20 @@ import {
2323
ViewChild,
2424
ViewEncapsulation,
2525
} from '@angular/core';
26-
import {animationFrameScheduler, asapScheduler, Observable, Subject, Observer} from 'rxjs';
26+
import {
27+
animationFrameScheduler,
28+
asapScheduler,
29+
Observable,
30+
Subject,
31+
Observer,
32+
Subscription,
33+
} from 'rxjs';
2734
import {auditTime, startWith, takeUntil} from 'rxjs/operators';
2835
import {ScrollDispatcher} from './scroll-dispatcher';
2936
import {CdkScrollable, ExtendedScrollToOptions} from './scrollable';
3037
import {CdkVirtualForOf} from './virtual-for-of';
3138
import {VIRTUAL_SCROLL_STRATEGY, VirtualScrollStrategy} from './virtual-scroll-strategy';
32-
39+
import {ViewportRuler} from './viewport-ruler';
3340

3441
/** Checks if the given ranges are equal. */
3542
function rangesEqual(r1: ListRange, r2: ListRange): boolean {
@@ -142,18 +149,33 @@ export class CdkVirtualScrollViewport extends CdkScrollable implements OnInit, O
142149
/** A list of functions to run after the next change detection cycle. */
143150
private _runAfterChangeDetection: Function[] = [];
144151

152+
/** Subscription to changes in the viewport size. */
153+
private _viewportChanges = Subscription.EMPTY;
154+
145155
constructor(public elementRef: ElementRef<HTMLElement>,
146156
private _changeDetectorRef: ChangeDetectorRef,
147157
ngZone: NgZone,
148158
@Optional() @Inject(VIRTUAL_SCROLL_STRATEGY)
149159
private _scrollStrategy: VirtualScrollStrategy,
150160
@Optional() dir: Directionality,
151-
scrollDispatcher: ScrollDispatcher) {
161+
scrollDispatcher: ScrollDispatcher,
162+
/**
163+
* @deprecated `viewportRuler` parameter to become required.
164+
* @breaking-change 11.0.0
165+
*/
166+
@Optional() viewportRuler?: ViewportRuler) {
152167
super(elementRef, scrollDispatcher, ngZone, dir);
153168

154169
if (!_scrollStrategy) {
155170
throw Error('Error: cdk-virtual-scroll-viewport requires the "itemSize" property to be set.');
156171
}
172+
173+
// @breaking-change 11.0.0 Remove null check for `viewportRuler`.
174+
if (viewportRuler) {
175+
this._viewportChanges = viewportRuler.change().subscribe(() => {
176+
this.checkViewportSize();
177+
});
178+
}
157179
}
158180

159181
ngOnInit() {
@@ -188,6 +210,7 @@ export class CdkVirtualScrollViewport extends CdkScrollable implements OnInit, O
188210
// Complete all subjects
189211
this._renderedRangeSubject.complete();
190212
this._detachedSubject.complete();
213+
this._viewportChanges.unsubscribe();
191214

192215
super.ngOnDestroy();
193216
}

tools/public_api_guard/cdk/scrolling.d.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,8 @@ export declare class CdkVirtualScrollViewport extends CdkScrollable implements O
105105
orientation: 'horizontal' | 'vertical';
106106
renderedRangeStream: Observable<ListRange>;
107107
scrolledIndexChange: Observable<number>;
108-
constructor(elementRef: ElementRef<HTMLElement>, _changeDetectorRef: ChangeDetectorRef, ngZone: NgZone, _scrollStrategy: VirtualScrollStrategy, dir: Directionality, scrollDispatcher: ScrollDispatcher);
108+
constructor(elementRef: ElementRef<HTMLElement>, _changeDetectorRef: ChangeDetectorRef, ngZone: NgZone, _scrollStrategy: VirtualScrollStrategy, dir: Directionality, scrollDispatcher: ScrollDispatcher,
109+
viewportRuler?: ViewportRuler);
109110
attach(forOf: CdkVirtualForOf<any>): void;
110111
checkViewportSize(): void;
111112
detach(): void;

0 commit comments

Comments
 (0)