Skip to content

Commit

Permalink
fix(scrolling): update virtual scroll viewport size on resize (#18058)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
crisbeto authored and mmalerba committed Dec 29, 2019
1 parent 99af8e9 commit c36466c
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 5 deletions.
21 changes: 20 additions & 1 deletion src/cdk/scrolling/virtual-scroll-viewport.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,15 @@ import {
Directive,
ViewContainerRef
} from '@angular/core';
import {async, ComponentFixture, fakeAsync, flush, inject, TestBed} from '@angular/core/testing';
import {
async,
ComponentFixture,
fakeAsync,
flush,
inject,
TestBed,
tick,
} from '@angular/core/testing';
import {animationFrameScheduler, Subject} from 'rxjs';


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

it('should update the viewport size when the page viewport changes', fakeAsync(() => {
finishInit(fixture);
spyOn(viewport, 'checkViewportSize').and.callThrough();

dispatchFakeEvent(window, 'resize');
fixture.detectChanges();
tick(20); // The resize listener is debounced so we need to flush it.

expect(viewport.checkViewportSize).toHaveBeenCalled();
}));

it('should get the rendered range', fakeAsync(() => {
finishInit(fixture);

Expand Down
29 changes: 26 additions & 3 deletions src/cdk/scrolling/virtual-scroll-viewport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,20 @@ import {
ViewChild,
ViewEncapsulation,
} from '@angular/core';
import {animationFrameScheduler, asapScheduler, Observable, Subject, Observer} from 'rxjs';
import {
animationFrameScheduler,
asapScheduler,
Observable,
Subject,
Observer,
Subscription,
} from 'rxjs';
import {auditTime, startWith, takeUntil} from 'rxjs/operators';
import {ScrollDispatcher} from './scroll-dispatcher';
import {CdkScrollable, ExtendedScrollToOptions} from './scrollable';
import {CdkVirtualForOf} from './virtual-for-of';
import {VIRTUAL_SCROLL_STRATEGY, VirtualScrollStrategy} from './virtual-scroll-strategy';

import {ViewportRuler} from './viewport-ruler';

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

/** Subscription to changes in the viewport size. */
private _viewportChanges = Subscription.EMPTY;

constructor(public elementRef: ElementRef<HTMLElement>,
private _changeDetectorRef: ChangeDetectorRef,
ngZone: NgZone,
@Optional() @Inject(VIRTUAL_SCROLL_STRATEGY)
private _scrollStrategy: VirtualScrollStrategy,
@Optional() dir: Directionality,
scrollDispatcher: ScrollDispatcher) {
scrollDispatcher: ScrollDispatcher,
/**
* @deprecated `viewportRuler` parameter to become required.
* @breaking-change 11.0.0
*/
@Optional() viewportRuler?: ViewportRuler) {
super(elementRef, scrollDispatcher, ngZone, dir);

if (!_scrollStrategy) {
throw Error('Error: cdk-virtual-scroll-viewport requires the "itemSize" property to be set.');
}

// @breaking-change 11.0.0 Remove null check for `viewportRuler`.
if (viewportRuler) {
this._viewportChanges = viewportRuler.change().subscribe(() => {
this.checkViewportSize();
});
}
}

ngOnInit() {
Expand Down Expand Up @@ -188,6 +210,7 @@ export class CdkVirtualScrollViewport extends CdkScrollable implements OnInit, O
// Complete all subjects
this._renderedRangeSubject.complete();
this._detachedSubject.complete();
this._viewportChanges.unsubscribe();

super.ngOnDestroy();
}
Expand Down
3 changes: 2 additions & 1 deletion tools/public_api_guard/cdk/scrolling.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,8 @@ export declare class CdkVirtualScrollViewport extends CdkScrollable implements O
orientation: 'horizontal' | 'vertical';
renderedRangeStream: Observable<ListRange>;
scrolledIndexChange: Observable<number>;
constructor(elementRef: ElementRef<HTMLElement>, _changeDetectorRef: ChangeDetectorRef, ngZone: NgZone, _scrollStrategy: VirtualScrollStrategy, dir: Directionality, scrollDispatcher: ScrollDispatcher);
constructor(elementRef: ElementRef<HTMLElement>, _changeDetectorRef: ChangeDetectorRef, ngZone: NgZone, _scrollStrategy: VirtualScrollStrategy, dir: Directionality, scrollDispatcher: ScrollDispatcher,
viewportRuler?: ViewportRuler);
attach(forOf: CdkVirtualForOf<any>): void;
checkViewportSize(): void;
detach(): void;
Expand Down

0 comments on commit c36466c

Please sign in to comment.