Skip to content

Commit 8922100

Browse files
crisbetojelbourn
authored andcommitted
fix(virtual-scroll): not removing view from container if it's outside the template cache (#13916)
Currently when detaching a view, we check whether it would fit in the cache, and if it doesn't, we destroy it. Since we destroy the view on it's own, the `ViewContainerRef` still has a reference to it, which means that we'll trigger change detection on it the next time the data changes. These changes switch to destroying the view through the view container. Fixes #13901.
1 parent 85e4a1d commit 8922100

File tree

2 files changed

+28
-1
lines changed

2 files changed

+28
-1
lines changed

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

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -324,7 +324,16 @@ export class CdkVirtualForOf<T> implements CollectionViewer, DoCheck, OnDestroy
324324
if (this._templateCache.length < this.cdkVirtualForTemplateCacheSize) {
325325
this._templateCache.push(view);
326326
} else {
327-
view.destroy();
327+
const index = this._viewContainerRef.indexOf(view);
328+
329+
// It's very unlikely that the index will ever be -1, but just in case,
330+
// destroy the view on its own, otherwise destroy it through the
331+
// container to ensure that all the references are removed.
332+
if (index === -1) {
333+
view.destroy();
334+
} else {
335+
this._viewContainerRef.remove(index);
336+
}
328337
}
329338
}
330339

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

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -611,6 +611,24 @@ describe('CdkVirtualScrollViewport', () => {
611611
finishInit(fixture);
612612
expect(zoneTest).toHaveBeenCalledWith(true);
613613
}));
614+
615+
it('should not throw when disposing of a view that will not fit in the cache', fakeAsync(() => {
616+
finishInit(fixture);
617+
testComponent.items = new Array(200).fill(0);
618+
testComponent.templateCacheSize = 1; // Reduce the cache size to something we can easily hit.
619+
fixture.detectChanges();
620+
flush();
621+
622+
expect(() => {
623+
for (let i = 0; i < 50; i++) {
624+
viewport.scrollToIndex(i);
625+
triggerScroll(viewport);
626+
fixture.detectChanges();
627+
flush();
628+
}
629+
}).not.toThrow();
630+
}));
631+
614632
});
615633

616634
describe('with RTL direction', () => {

0 commit comments

Comments
 (0)