Skip to content

Commit 2ddc257

Browse files
tinayuangaojosephperrott
authored andcommitted
fix(tree): improve nested tree node & fix nested tree control (#10454)
1 parent 1659004 commit 2ddc257

File tree

5 files changed

+31
-27
lines changed

5 files changed

+31
-27
lines changed

src/cdk/tree/control/nested-tree-control.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,16 +25,17 @@ export class NestedTreeControl<T> extends BaseTreeControl<T> {
2525
*/
2626
expandAll(): void {
2727
this.expansionModel.clear();
28-
let toBeExpanded = <any>[];
29-
this.dataNodes.forEach(dataNode => toBeExpanded.push(...this.getDescendants(dataNode)));
30-
this.expansionModel.select(...toBeExpanded);
28+
const allNodes = this.dataNodes.reduce((accumulator, dataNode) =>
29+
[...accumulator, ...this.getDescendants(dataNode), dataNode], []);
30+
this.expansionModel.select(...allNodes);
3131
}
3232

3333
/** Gets a list of descendant dataNodes of a subtree rooted at given data node recursively. */
3434
getDescendants(dataNode: T): T[] {
3535
const descendants = [];
3636
this._getDescendants(descendants, dataNode);
37-
return descendants;
37+
// Remove the node itself
38+
return descendants.splice(1);
3839
}
3940

4041
/** A helper function to get descendants recursively. */

src/cdk/tree/nested-node.ts

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import {
1010
ContentChildren,
1111
Directive,
1212
ElementRef,
13+
IterableDiffers,
14+
IterableDiffer,
1315
OnDestroy,
1416
QueryList,
1517
} from '@angular/core';
@@ -51,32 +53,33 @@ import {getTreeControlFunctionsMissingError} from './tree-errors';
5153
providers: [{provide: CdkTreeNode, useExisting: CdkNestedTreeNode}]
5254
})
5355
export class CdkNestedTreeNode<T> extends CdkTreeNode<T> implements AfterContentInit, OnDestroy {
56+
/** Differ used to find the changes in the data provided by the data source. */
57+
private _dataDiffer: IterableDiffer<T>;
58+
5459
/** The children data dataNodes of current node. They will be placed in `CdkTreeNodeOutlet`. */
5560
protected _children: T[];
5661

5762
/** The children node placeholder. */
5863
@ContentChildren(CdkTreeNodeOutlet) nodeOutlet: QueryList<CdkTreeNodeOutlet>;
5964

6065
constructor(protected _elementRef: ElementRef,
61-
protected _tree: CdkTree<T>) {
66+
protected _tree: CdkTree<T>,
67+
protected _differs: IterableDiffers) {
6268
super(_elementRef, _tree);
6369
}
6470

6571
ngAfterContentInit() {
72+
this._dataDiffer = this._differs.find([]).create();
6673
if (!this._tree.treeControl.getChildren) {
6774
throw getTreeControlFunctionsMissingError();
6875
}
6976
this._tree.treeControl.getChildren(this.data).pipe(takeUntil(this._destroyed))
7077
.subscribe(result => {
71-
if (result && result.length) {
72-
// In case when nodeOutlet is not in the DOM when children changes, save it in the node
73-
// and add to nodeOutlet when it's available.
74-
this._children = result as T[];
75-
this._addChildrenNodes();
76-
}
78+
this._children = result;
79+
this.updateChildrenNodes();
7780
});
7881
this.nodeOutlet.changes.pipe(takeUntil(this._destroyed))
79-
.subscribe((_) => this._addChildrenNodes());
82+
.subscribe((_) => this.updateChildrenNodes());
8083
}
8184

8285
ngOnDestroy() {
@@ -86,12 +89,10 @@ export class CdkNestedTreeNode<T> extends CdkTreeNode<T> implements AfterContent
8689
}
8790

8891
/** Add children dataNodes to the NodeOutlet */
89-
protected _addChildrenNodes(): void {
90-
this._clear();
91-
if (this.nodeOutlet.length && this._children && this._children.length) {
92-
this._children.forEach((child, index) => {
93-
this._tree.insertNode(child, index, this.nodeOutlet.first.viewContainer);
94-
});
92+
protected updateChildrenNodes(): void {
93+
if (this.nodeOutlet.length && this._children) {
94+
const viewContainer = this.nodeOutlet.first.viewContainer;
95+
this._tree.renderNodeChanges(this._children, this._dataDiffer, viewContainer);
9596
}
9697
}
9798

src/cdk/tree/tree.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -259,22 +259,22 @@ export class CdkTree<T> implements CollectionViewer, OnInit, OnDestroy {
259259

260260
if (dataStream) {
261261
this._dataSubscription = dataStream.pipe(takeUntil(this._onDestroy))
262-
.subscribe(data => this._renderNodeChanges(data));
262+
.subscribe(data => this.renderNodeChanges(data));
263263
} else {
264264
throw getTreeNoValidDataSourceError();
265265
}
266266
}
267267

268268
/** Check for changes made in the data and render each change (node added/removed/moved). */
269-
private _renderNodeChanges(dataNodes: T[]) {
270-
const changes = this._dataDiffer.diff(dataNodes);
269+
renderNodeChanges(data: T[], dataDiffer: IterableDiffer<T> = this._dataDiffer,
270+
viewContainer: ViewContainerRef = this._nodeOutlet.viewContainer) {
271+
const changes = dataDiffer.diff(data);
271272
if (!changes) { return; }
272273

273-
const viewContainer = this._nodeOutlet.viewContainer;
274274
changes.forEachOperation(
275275
(item: IterableChangeRecord<T>, adjustedPreviousIndex: number, currentIndex: number) => {
276276
if (item.previousIndex == null) {
277-
this.insertNode(dataNodes[currentIndex], currentIndex);
277+
this.insertNode(data[currentIndex], currentIndex, viewContainer);
278278
} else if (currentIndex == null) {
279279
viewContainer.remove(adjustedPreviousIndex);
280280
} else {

src/demo-app/tree/tree-demo.html

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,11 @@
2323
<mat-expansion-panel>
2424
<mat-expansion-panel-header>Nested tree</mat-expansion-panel-header>
2525
<mat-tree [dataSource]="nestedDataSource" [treeControl]="nestedTreeControl">
26-
<mat-tree-node *matTreeNodeDef="let node" matTreeNodeToggle>
27-
<li>
26+
<mat-nested-tree-node *matTreeNodeDef="let node" matTreeNodeToggle>
27+
<li class="mat-tree-node">
2828
<div>{{node.filename}}: {{node.type}}</div>
2929
</li>
30-
</mat-tree-node>
30+
</mat-nested-tree-node>
3131
<mat-nested-tree-node *matTreeNodeDef="let node; when: hasNestedChild">
3232
<li>
3333
<div class="mat-tree-node">

src/lib/tree/node.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
Directive,
1313
ElementRef,
1414
Input,
15+
IterableDiffers,
1516
QueryList
1617
} from '@angular/core';
1718
import {
@@ -94,8 +95,9 @@ export class MatNestedTreeNode<T> extends _MatNestedTreeNodeMixinBase<T>
9495

9596
constructor(protected _elementRef: ElementRef,
9697
protected _tree: CdkTree<T>,
98+
protected _differs: IterableDiffers,
9799
@Attribute('tabindex') tabIndex: string) {
98-
super(_elementRef, _tree);
100+
super(_elementRef, _tree, _differs);
99101

100102
this.tabIndex = Number(tabIndex) || 0;
101103
}

0 commit comments

Comments
 (0)