@@ -75,12 +75,12 @@ type RenderingData<T> =
75
75
| {
76
76
flattenedNodes : null ;
77
77
nodeType : null ;
78
- renderNodes : T [ ] ;
78
+ renderNodes : readonly T [ ] ;
79
79
}
80
80
| {
81
- flattenedNodes : T [ ] ;
81
+ flattenedNodes : readonly T [ ] ;
82
82
nodeType : 'nested' | 'flat' ;
83
- renderNodes : [ ] ;
83
+ renderNodes : readonly T [ ] ;
84
84
} ;
85
85
86
86
/**
@@ -342,6 +342,14 @@ export class CdkTree<T, K = T>
342
342
}
343
343
}
344
344
345
+ private _getExpansionModel ( ) {
346
+ if ( ! this . treeControl ) {
347
+ this . _expansionModel ??= new SelectionModel < K > ( true ) ;
348
+ return this . _expansionModel ;
349
+ }
350
+ return this . treeControl . expansionModel ;
351
+ }
352
+
345
353
/** Set up a subscription for the data provided by the data source. */
346
354
private _subscribeToDataChanges ( ) {
347
355
if ( this . _dataSubscription ) {
@@ -365,15 +373,17 @@ export class CdkTree<T, K = T>
365
373
return ;
366
374
}
367
375
368
- let expansionModel ;
369
- if ( ! this . treeControl ) {
370
- this . _expansionModel = new SelectionModel < K > ( true ) ;
371
- expansionModel = this . _expansionModel ;
372
- } else {
373
- expansionModel = this . treeControl . expansionModel ;
374
- }
376
+ this . _dataSubscription = this . _getRenderData ( dataStream )
377
+ . pipe ( takeUntil ( this . _onDestroy ) )
378
+ . subscribe ( renderingData => {
379
+ this . _renderDataChanges ( renderingData ) ;
380
+ } ) ;
381
+ }
375
382
376
- this . _dataSubscription = combineLatest ( [
383
+ /** Given an Observable containing a stream of the raw data, returns an Observable containing the RenderingData */
384
+ private _getRenderData ( dataStream : Observable < readonly T [ ] > ) : Observable < RenderingData < T > > {
385
+ const expansionModel = this . _getExpansionModel ( ) ;
386
+ return combineLatest ( [
377
387
dataStream ,
378
388
this . _nodeType ,
379
389
// We don't use the expansion data directly, however we add it here to essentially
@@ -384,24 +394,19 @@ export class CdkTree<T, K = T>
384
394
this . _emitExpansionChanges ( expansionChanges ) ;
385
395
} ) ,
386
396
) ,
387
- ] )
388
- . pipe (
389
- switchMap ( ( [ data , nodeType ] ) => {
390
- if ( nodeType === null ) {
391
- return observableOf ( [ { renderNodes : data } , nodeType ] as const ) ;
392
- }
397
+ ] ) . pipe (
398
+ switchMap ( ( [ data , nodeType ] ) => {
399
+ if ( nodeType === null ) {
400
+ return observableOf ( { renderNodes : data , flattenedNodes : null , nodeType} as const ) ;
401
+ }
393
402
394
- // If we're here, then we know what our node type is, and therefore can
395
- // perform our usual rendering pipeline, which necessitates converting the data
396
- return this . _convertData ( data , nodeType ) . pipe (
397
- map ( convertedData => [ convertedData , nodeType ] as const ) ,
398
- ) ;
399
- } ) ,
400
- takeUntil ( this . _onDestroy ) ,
401
- )
402
- . subscribe ( ( [ data , nodeType ] ) => {
403
- this . _renderDataChanges ( { nodeType, ...data } as RenderingData < T > ) ;
404
- } ) ;
403
+ // If we're here, then we know what our node type is, and therefore can
404
+ // perform our usual rendering pipeline, which necessitates converting the data
405
+ return this . _computeRenderingData ( data , nodeType ) . pipe (
406
+ map ( convertedData => ( { ...convertedData , nodeType} ) as const ) ,
407
+ ) ;
408
+ } ) ,
409
+ ) ;
405
410
}
406
411
407
412
private _renderDataChanges ( data : RenderingData < T > ) {
@@ -586,10 +591,9 @@ export class CdkTree<T, K = T>
586
591
587
592
/** Whether the data node is expanded or collapsed. Returns true if it's expanded. */
588
593
isExpanded ( dataNode : T ) : boolean {
589
- return (
590
- this . treeControl ?. isExpanded ( dataNode ) ??
591
- this . _expansionModel ?. isSelected ( this . _getExpansionKey ( dataNode ) ) ??
592
- false
594
+ return ! ! (
595
+ this . treeControl ?. isExpanded ( dataNode ) ||
596
+ this . _expansionModel ?. isSelected ( this . _getExpansionKey ( dataNode ) )
593
597
) ;
594
598
}
595
599
@@ -733,26 +737,13 @@ export class CdkTree<T, K = T>
733
737
if ( ! expanded ) {
734
738
return [ ] ;
735
739
}
736
- const startIndex = flattenedNodes . findIndex ( node => this . _getExpansionKey ( node ) === key ) ;
737
- const level = levelAccessor ( dataNode ) + 1 ;
738
- const results : T [ ] = [ ] ;
739
-
740
- // Goes through flattened tree nodes in the `flattenedNodes` array, and get all direct
741
- // descendants. The level of descendants of a tree node must be equal to the level of the
742
- // given tree node + 1.
743
- // If we reach a node whose level is equal to the level of the tree node, we hit a sibling.
744
- // If we reach a node whose level is greater than the level of the tree node, we hit a
745
- // sibling of an ancestor.
746
- for ( let i = startIndex + 1 ; i < flattenedNodes . length ; i ++ ) {
747
- const currentLevel = levelAccessor ( flattenedNodes [ i ] ) ;
748
- if ( level > currentLevel ) {
749
- break ;
750
- }
751
- if ( level === currentLevel ) {
752
- results . push ( flattenedNodes [ i ] ) ;
753
- }
754
- }
755
- return results ;
740
+ return this . _findChildrenByLevel (
741
+ levelAccessor ,
742
+ flattenedNodes ,
743
+
744
+ dataNode ,
745
+ 1 ,
746
+ ) ;
756
747
} ) ,
757
748
) ;
758
749
}
@@ -763,6 +754,42 @@ export class CdkTree<T, K = T>
763
754
throw getTreeControlMissingError ( ) ;
764
755
}
765
756
757
+ /**
758
+ * Given the list of flattened nodes, the level accessor, and the level range within
759
+ * which to consider children, finds the children for a given node.
760
+ *
761
+ * For example, for direct children, `levelDelta` would be 1. For all descendants,
762
+ * `levelDelta` would be Infinity.
763
+ */
764
+ private _findChildrenByLevel (
765
+ levelAccessor : ( node : T ) => number ,
766
+ flattenedNodes : readonly T [ ] ,
767
+ dataNode : T ,
768
+ levelDelta : number ,
769
+ ) : T [ ] {
770
+ const key = this . _getExpansionKey ( dataNode ) ;
771
+ const startIndex = flattenedNodes . findIndex ( node => this . _getExpansionKey ( node ) === key ) ;
772
+ const dataNodeLevel = levelAccessor ( dataNode ) ;
773
+ const expectedLevel = dataNodeLevel + levelDelta ;
774
+ const results : T [ ] = [ ] ;
775
+
776
+ // Goes through flattened tree nodes in the `flattenedNodes` array, and get all
777
+ // descendants within a certain level range.
778
+ //
779
+ // If we reach a node whose level is equal to or less than the level of the tree node,
780
+ // we hit a sibling or parent's sibling, and should stop.
781
+ for ( let i = startIndex + 1 ; i < flattenedNodes . length ; i ++ ) {
782
+ const currentLevel = levelAccessor ( flattenedNodes [ i ] ) ;
783
+ if ( currentLevel <= dataNodeLevel ) {
784
+ break ;
785
+ }
786
+ if ( currentLevel <= expectedLevel ) {
787
+ results . push ( flattenedNodes [ i ] ) ;
788
+ }
789
+ }
790
+ return results ;
791
+ }
792
+
766
793
/**
767
794
* Adds the specified node component to the tree's internal registry.
768
795
*
@@ -842,27 +869,12 @@ export class CdkTree<T, K = T>
842
869
return observableOf ( this . treeControl . getDescendants ( dataNode ) ) ;
843
870
}
844
871
if ( this . levelAccessor ) {
845
- const key = this . _getExpansionKey ( dataNode ) ;
846
- const startIndex = this . _flattenedNodes . value . findIndex (
847
- node => this . _getExpansionKey ( node ) === key ,
872
+ const results = this . _findChildrenByLevel (
873
+ this . levelAccessor ,
874
+ this . _flattenedNodes . value ,
875
+ dataNode ,
876
+ Infinity ,
848
877
) ;
849
- const results : T [ ] = [ ] ;
850
-
851
- // Goes through flattened tree nodes in the `dataNodes` array, and get all descendants.
852
- // The level of descendants of a tree node must be greater than the level of the given
853
- // tree node.
854
- // If we reach a node whose level is equal to the level of the tree node, we hit a sibling.
855
- // If we reach a node whose level is greater than the level of the tree node, we hit a
856
- // sibling of an ancestor.
857
- const currentLevel = this . levelAccessor ( dataNode ) ;
858
- for (
859
- let i = startIndex + 1 ;
860
- i < this . _flattenedNodes . value . length &&
861
- currentLevel < this . levelAccessor ( this . _flattenedNodes . value [ i ] ) ;
862
- i ++
863
- ) {
864
- results . push ( this . _flattenedNodes . value [ i ] ) ;
865
- }
866
878
return observableOf ( results ) ;
867
879
}
868
880
if ( this . childrenAccessor ) {
@@ -1003,7 +1015,7 @@ export class CdkTree<T, K = T>
1003
1015
*
1004
1016
* This also computes parent, level, and group data.
1005
1017
*/
1006
- private _convertData (
1018
+ private _computeRenderingData (
1007
1019
nodes : readonly T [ ] ,
1008
1020
nodeType : 'flat' | 'nested' ,
1009
1021
) : Observable < {
0 commit comments