Skip to content

Commit 8494f03

Browse files
crisbetojelbourn
authored andcommitted
fix(scrolling): virtual scroll not disconnecting from data source on destroy (#15856)
Fixes the `CdkVirtualForOf` not calling `disconnect` on its current data source when it's destroyed. Fixes #15855.
1 parent 2e18570 commit 8494f03

File tree

2 files changed

+21
-3
lines changed

2 files changed

+21
-3
lines changed

src/cdk/scrolling/virtual-for-of.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ import {
3030
TrackByFunction,
3131
ViewContainerRef,
3232
} from '@angular/core';
33-
import {Observable, Subject} from 'rxjs';
33+
import {Observable, Subject, of as observableOf} from 'rxjs';
3434
import {pairwise, shareReplay, startWith, switchMap, takeUntil} from 'rxjs/operators';
3535
import {CdkVirtualScrollViewport} from './virtual-scroll-viewport';
3636

@@ -238,6 +238,7 @@ export class CdkVirtualForOf<T> implements CollectionViewer, DoCheck, OnDestroy
238238
ngOnDestroy() {
239239
this._viewport.detach();
240240

241+
this._dataSourceChanges.next();
241242
this._dataSourceChanges.complete();
242243
this.viewChange.complete();
243244

@@ -262,15 +263,15 @@ export class CdkVirtualForOf<T> implements CollectionViewer, DoCheck, OnDestroy
262263
}
263264

264265
/** Swap out one `DataSource` for another. */
265-
private _changeDataSource(oldDs: DataSource<T> | null, newDs: DataSource<T>):
266+
private _changeDataSource(oldDs: DataSource<T> | null, newDs: DataSource<T> | null):
266267
Observable<T[] | ReadonlyArray<T>> {
267268

268269
if (oldDs) {
269270
oldDs.disconnect(this);
270271
}
271272

272273
this._needsUpdate = true;
273-
return newDs.connect(this);
274+
return newDs ? newDs.connect(this) : observableOf();
274275
}
275276

276277
/** Update the `CdkVirtualForOfContext` for all views. */

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

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -485,6 +485,23 @@ describe('CdkVirtualScrollViewport', () => {
485485
.toEqual({start: 0, end: 3}, 'newly emitted items should be rendered');
486486
}));
487487

488+
it('should disconnect from data source on destroy', fakeAsync(() => {
489+
const data = new Subject<number[]>();
490+
const dataSource = new ArrayDataSource(data);
491+
492+
spyOn(dataSource, 'connect').and.callThrough();
493+
spyOn(dataSource, 'disconnect').and.callThrough();
494+
495+
testComponent.items = dataSource as any;
496+
finishInit(fixture);
497+
498+
expect(dataSource.connect).toHaveBeenCalled();
499+
500+
fixture.destroy();
501+
502+
expect(dataSource.disconnect).toHaveBeenCalled();
503+
}));
504+
488505
it('should trackBy value by default', fakeAsync(() => {
489506
testComponent.items = [];
490507
spyOn(testComponent.virtualForOf, '_detachView').and.callThrough();

0 commit comments

Comments
 (0)