@@ -93,6 +93,20 @@ export class CdkTree<T, K = T> implements AfterContentChecked, CollectionViewer,
9393 /** Level of nodes */
9494 private _levels : Map < T , number > = new Map < T , number > ( ) ;
9595
96+ /** The immediate parents for a node. This is `null` if there is no parent. */
97+ private _parents : Map < T , T | null > = new Map < T , T | null > ( ) ;
98+
99+ /**
100+ * The internal node groupings for each node; we use this, primarily for flattened trees, to
101+ * determine where a particular node is within each group.
102+ *
103+ * The structure of this is that:
104+ * - the outer index is the level
105+ * - the inner index is the parent node for this particular group. If there is no parent node, we
106+ * use `null`.
107+ */
108+ private _groups : Map < number , Map < T | null , T [ ] > > = new Map < number , Map < T | null , T [ ] > > ( ) ;
109+
96110 /**
97111 * Provides a stream containing the latest data array to render. Influenced by the tree's
98112 * stream of view window (what dataNodes are currently on screen).
@@ -295,7 +309,10 @@ export class CdkTree<T, K = T> implements AfterContentChecked, CollectionViewer,
295309 this . insertNode ( data [ currentIndex ! ] , currentIndex ! , viewContainer , parentData ) ;
296310 } else if ( currentIndex == null ) {
297311 viewContainer . remove ( adjustedPreviousIndex ! ) ;
312+ const group = this . _getNodeGroup ( item . item ) ;
298313 this . _levels . delete ( item . item ) ;
314+ this . _parents . delete ( item . item ) ;
315+ group . splice ( group . indexOf ( item . item ) , 1 ) ;
299316 } else {
300317 const view = viewContainer . get ( adjustedPreviousIndex ! ) ;
301318 viewContainer . move ( view ! , currentIndex ) ;
@@ -348,6 +365,19 @@ export class CdkTree<T, K = T> implements AfterContentChecked, CollectionViewer,
348365 context . level = 0 ;
349366 }
350367 this . _levels . set ( nodeData , context . level ) ;
368+ const parent = parentData ?? this . _findParentForNode ( nodeData , index ) ;
369+ this . _parents . set ( nodeData , parent ) ;
370+
371+ // Determine where to insert this new node into the group, then insert it.
372+ // We do this by looking at the previous node in our flattened node list. If it's in the same
373+ // group, we place the current node after. Otherwise, we place it at the start of the group.
374+ const currentGroup = this . _groups . get ( context . level ) ?? new Map < T | null , T [ ] > ( ) ;
375+ const group = currentGroup . get ( parent ) ?? [ ] ;
376+ const previousNode = this . _dataNodes ?. [ index - 1 ] ;
377+ const groupInsertionIndex = ( previousNode && group . indexOf ( previousNode ) + 1 ) ?? 0 ;
378+ group . splice ( groupInsertionIndex , 0 , nodeData ) ;
379+ currentGroup . set ( parent , group ) ;
380+ this . _groups . set ( context . level , currentGroup ) ;
351381
352382 // Use default tree nodeOutlet, or nested node's nodeOutlet
353383 const container = viewContainer ? viewContainer : this . _nodeOutlet . viewContainer ;
@@ -546,6 +576,32 @@ export class CdkTree<T, K = T> implements AfterContentChecked, CollectionViewer,
546576 private _trackExpansionKey ( dataNode : T ) : K {
547577 return this . expansionKey ?.( dataNode ) ?? ( dataNode as unknown as K ) ;
548578 }
579+
580+ private _getNodeGroup ( node : T ) {
581+ const level = this . _levels . get ( node ) ;
582+ const parent = this . _parents . get ( node ) ;
583+ const group = this . _groups . get ( level ?? 0 ) ?. get ( parent ?? null ) ;
584+ return group ?? [ node ] ;
585+ }
586+
587+ private _findParentForNode ( node : T , index : number ) {
588+ // In all cases, we have a mapping from node to level; all we need to do here is backtrack in
589+ // our flattened list of nodes to determine the first node that's of a level lower than the
590+ // provided node.
591+ if ( ! this . _dataNodes ) {
592+ return null ;
593+ }
594+ const currentLevel = this . _levels . get ( node ) ?? 0 ;
595+ for ( let parentIndex = index ; parentIndex >= 0 ; parentIndex -- ) {
596+ const parentNode = this . _dataNodes [ parentIndex ] ;
597+ const parentLevel = this . _levels . get ( parentNode ) ?? 0 ;
598+
599+ if ( parentLevel < currentLevel ) {
600+ return parentNode ;
601+ }
602+ }
603+ return null ;
604+ }
549605}
550606
551607/**
0 commit comments