diff --git a/src/cdk/tree/tree.spec.ts b/src/cdk/tree/tree.spec.ts index 96321621afb9..824ac56d5b61 100644 --- a/src/cdk/tree/tree.spec.ts +++ b/src/cdk/tree/tree.spec.ts @@ -1481,6 +1481,32 @@ describe('CdkTree', () => { .withContext(`expect an expanded node`) .toBe(1); }); + + it('should expand/collapse all nested nodes when calling expandAll/collapseAll', () => { + configureCdkTreeTestingModule([IsExpandableOrderingTest]); + const fixture = TestBed.createComponent(IsExpandableOrderingTest); + const component = fixture.componentInstance; + const data = fixture.componentInstance.dataSource; + treeElement = fixture.nativeElement.querySelector('cdk-tree'); + + data[0].children[0].children.push(new MinimalTestData('extra')); + data[0].children[0].children[0].children.push(new MinimalTestData('extra')); + fixture.detectChanges(); + + component.tree.expandAll(); + fixture.detectChanges(); + expect(getNodes(treeElement).map(n => n.getAttribute('aria-expanded'))).toEqual([ + 'true', + 'true', + 'true', + 'true', + ]); + + component.tree.collapseAll(); + fixture.detectChanges(); + + expect(getNodes(treeElement).map(n => n.getAttribute('aria-expanded'))).toEqual(['false']); + }); }); export class TestData { @@ -1698,10 +1724,6 @@ class SimpleCdkTreeApp { @ViewChild(CdkTree) tree: CdkTree; @ViewChildren(CdkTreeNodePadding) paddingNodes: QueryList>; - - expandAll() { - this.tree.expandAll(); - } } @Component({ diff --git a/src/cdk/tree/tree.ts b/src/cdk/tree/tree.ts index c7daf68f9fd1..5a27c8bb479f 100644 --- a/src/cdk/tree/tree.ts +++ b/src/cdk/tree/tree.ts @@ -716,10 +716,7 @@ export class CdkTree if (this.treeControl) { this.treeControl.expandAll(); } else if (this._expansionModel) { - const expansionModel = this._expansionModel; - expansionModel.select( - ...this._flattenedNodes.value.map(child => this._getExpansionKey(child)), - ); + this._forEachExpansionKey(keys => this._expansionModel?.select(...keys)); } } @@ -728,10 +725,7 @@ export class CdkTree if (this.treeControl) { this.treeControl.collapseAll(); } else if (this._expansionModel) { - const expansionModel = this._expansionModel; - expansionModel.deselect( - ...this._flattenedNodes.value.map(child => this._getExpansionKey(child)), - ); + this._forEachExpansionKey(keys => this._expansionModel?.deselect(...keys)); } } @@ -776,13 +770,7 @@ export class CdkTree if (!expanded) { return []; } - return this._findChildrenByLevel( - levelAccessor, - flattenedNodes, - - dataNode, - 1, - ); + return this._findChildrenByLevel(levelAccessor, flattenedNodes, dataNode, 1); }), ); } @@ -1153,6 +1141,28 @@ export class CdkTree this._ariaSets.set(parentKey, group); } } + + /** Invokes a callback with all node expansion keys. */ + private _forEachExpansionKey(callback: (keys: K[]) => void) { + const toToggle: K[] = []; + const observables: Observable[] = []; + + this._nodes.value.forEach(node => { + toToggle.push(this._getExpansionKey(node.data)); + observables.push(this._getDescendants(node.data)); + }); + + if (observables.length > 0) { + combineLatest(observables) + .pipe(take(1), takeUntil(this._onDestroy)) + .subscribe(results => { + results.forEach(inner => inner.forEach(r => toToggle.push(this._getExpansionKey(r)))); + callback(toToggle); + }); + } else { + callback(toToggle); + } + } } /**