Skip to content

Commit f471445

Browse files
committed
fix(cdk/tree): fix test errors and children conversion; also make renderNodeChanges private
1 parent 004fb04 commit f471445

File tree

1 file changed

+34
-28
lines changed

1 file changed

+34
-28
lines changed

src/cdk/tree/tree.ts

Lines changed: 34 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ import {
4040
Subject,
4141
Subscription,
4242
} from 'rxjs';
43-
import {concatMap, map, reduce, startWith, switchMap, take, takeUntil} from 'rxjs/operators';
43+
import {concatMap, map, reduce, startWith, switchMap, take, takeUntil, tap} from 'rxjs/operators';
4444
import {TreeControl} from './control/tree-control';
4545
import {CdkTreeNodeDef, CdkTreeNodeOutletContext} from './node';
4646
import {CdkTreeNodeOutlet} from './outlet';
@@ -155,6 +155,8 @@ export class CdkTree<T, K = T> implements AfterContentChecked, CollectionViewer,
155155
*
156156
* This controls what selection of data the tree will render.
157157
*/
158+
// NB: we're unable to determine this ourselves; Angular's ContentChildren
159+
// unfortunately does not pick up the necessary information.
158160
@Input() nodeType?: 'flat' | 'nested';
159161

160162
// Outlets within the tree's template where the dataNodes will be inserted.
@@ -182,7 +184,11 @@ export class CdkTree<T, K = T> implements AfterContentChecked, CollectionViewer,
182184
/** Keep track of which nodes are expanded. */
183185
private _expansionModel?: SelectionModel<K>;
184186

185-
/** Maintain a synchronous cache of the currently known data nodes. */
187+
/**
188+
* Maintain a synchronous cache of the currently known data nodes. In the
189+
* case of nested nodes (i.e. if `nodeType` is 'nested'), this will
190+
* only contain the root nodes.
191+
*/
186192
private _dataNodes: BehaviorSubject<readonly T[]> = new BehaviorSubject<readonly T[]>([]);
187193

188194
/** The mapping between data and the node that is rendered. */
@@ -291,39 +297,22 @@ export class CdkTree<T, K = T> implements AfterContentChecked, CollectionViewer,
291297
if (dataStream) {
292298
this._dataSubscription = dataStream
293299
.pipe(
294-
switchMap(data => this._flattenChildren(data)),
300+
switchMap(data => this._convertChildren(data)),
295301
takeUntil(this._onDestroy),
296302
)
297-
.subscribe(data => this.renderNodeChanges(data));
303+
.subscribe(data => this._renderNodeChanges(data));
298304
} else if (typeof ngDevMode === 'undefined' || ngDevMode) {
299305
throw getTreeNoValidDataSourceError();
300306
}
301307
}
302308

303309
/** Check for changes made in the data and render each change (node added/removed/moved). */
304-
renderNodeChanges(
310+
_renderNodeChanges(
305311
data: readonly T[],
306312
dataDiffer: IterableDiffer<T> = this._dataDiffer,
307313
viewContainer: ViewContainerRef = this._nodeOutlet.viewContainer,
308314
parentData?: T,
309315
) {
310-
this._dataNodes.next(data);
311-
312-
this._renderNodeChanges(data, dataDiffer, viewContainer, parentData);
313-
}
314-
315-
/** Check for changes made in the data and render each change (node added/removed/moved). */
316-
_renderNodeChanges(
317-
data: readonly T[],
318-
dataDiffer: IterableDiffer<T>,
319-
viewContainer: ViewContainerRef,
320-
parentData?: T,
321-
) {
322-
const levelAccessor = this._getLevelAccessor();
323-
if (levelAccessor && this.nodeType === 'nested' && !parentData) {
324-
data = data.filter(data => levelAccessor(data) === 0);
325-
}
326-
327316
const changes = dataDiffer.diff(data);
328317
if (!changes) {
329318
return;
@@ -691,19 +680,36 @@ export class CdkTree<T, K = T> implements AfterContentChecked, CollectionViewer,
691680
return this.expansionKey?.(dataNode) ?? (dataNode as unknown as K);
692681
}
693682

694-
private _flattenChildren(nodes: readonly T[]): Observable<readonly T[]> {
695-
// If we're using TreeControl or levelAccessor, we don't need to manually
696-
// flatten things here.
697-
if (!this.childrenAccessor) {
698-
return observableOf(nodes);
699-
} else {
683+
/**
684+
* Converts children for certain tree configurations. Note also that this
685+
* caches the known nodes for use in other parts of the tree.
686+
*/
687+
private _convertChildren(nodes: readonly T[]): Observable<readonly T[]> {
688+
// The only situations where we have to convert children types is when
689+
// they're mismatched; i.e. if the tree is using a childrenAccessor and the
690+
// nodes are flat, or if the tree is using a levelAccessor and the nodes are
691+
// nested.
692+
if (this.childrenAccessor && this.nodeType === 'flat') {
693+
// This flattens children into a single array.
700694
return observableOf(...nodes).pipe(
701695
concatMap(node => concat(observableOf([node]), this._getAllChildrenRecursively(node))),
702696
reduce((results, nodes) => {
703697
results.push(...nodes);
704698
return results;
705699
}, [] as T[]),
700+
tap((nodes) => {
701+
this._dataNodes.next(nodes);
702+
}),
706703
);
704+
} else if (this.levelAccessor && this.nodeType === 'nested') {
705+
this._dataNodes.next(nodes);
706+
// In the nested case, we only look for root nodes. The CdkNestedNode
707+
// itself will handle rendering each individual node's children.
708+
const levelAccessor = this.levelAccessor;
709+
return observableOf(nodes.filter(node => levelAccessor(node) === 0));
710+
} else {
711+
this._dataNodes.next(nodes);
712+
return observableOf(nodes);
707713
}
708714
}
709715
}

0 commit comments

Comments
 (0)