diff --git a/src/cdk/tree/tree.spec.ts b/src/cdk/tree/tree.spec.ts index e7ffa605c7aa..a91038c61aa1 100644 --- a/src/cdk/tree/tree.spec.ts +++ b/src/cdk/tree/tree.spec.ts @@ -17,7 +17,7 @@ import {TreeControl} from './control/tree-control'; import {FlatTreeControl} from './control/flat-tree-control'; import {NestedTreeControl} from './control/nested-tree-control'; import {CdkTreeModule} from './index'; -import {CdkTree} from './tree'; +import {CdkTree, CdkTreeNode} from './tree'; import {getTreeControlFunctionsMissingError} from './tree-errors'; @@ -35,6 +35,20 @@ describe('CdkTree', () => { }).compileComponents(); } + it('should clear out the `mostRecentTreeNode` on destroy', () => { + configureCdkTreeTestingModule([SimpleCdkTreeApp]); + const fixture = TestBed.createComponent(SimpleCdkTreeApp); + fixture.detectChanges(); + + // Cast the assertions to a boolean to avoid Jasmine going into an + // infinite loop when stringifying the object, if the test starts failing. + expect(!!CdkTreeNode.mostRecentTreeNode).toBe(true); + + fixture.destroy(); + + expect(!!CdkTreeNode.mostRecentTreeNode).toBe(false); + }); + describe('flat tree', () => { describe('should initialize', () => { let fixture: ComponentFixture; diff --git a/src/cdk/tree/tree.ts b/src/cdk/tree/tree.ts index 11e4052ed8ac..e0ead62e1ca2 100644 --- a/src/cdk/tree/tree.ts +++ b/src/cdk/tree/tree.ts @@ -290,7 +290,7 @@ export class CdkTree 'class': 'cdk-tree-node', }, }) -export class CdkTreeNode implements FocusableOption, OnDestroy { +export class CdkTreeNode implements FocusableOption, OnDestroy { /** * The most recently created `CdkTreeNode`. We save it in static variable so we can retrieve it * in `CdkTree` and set the data to it. @@ -328,6 +328,12 @@ export class CdkTreeNode implements FocusableOption, OnDestroy { } ngOnDestroy() { + // If this is the last tree node being destroyed, + // clear out the reference to avoid leaking memory. + if (CdkTreeNode.mostRecentTreeNode === this) { + CdkTreeNode.mostRecentTreeNode = null; + } + this._destroyed.next(); this._destroyed.complete(); }