Search code examples
angulartypescriptangular-materialangular6angular-cdk

Get parent hierarchy from a child node in angular 6 material tree


I am following a tutorial to implement cdk tree in angular 6. I created a tree structure, now I want to get the parent hierarchy from from the child by making it clickable, while there are methods like getDescendants to get children of a node, vice versa is not available. How can I get the parent hierarchy from a child or leaf node.


Solution

  • I've added these methods to my tree component. Note that I use the flat tree, this won't work for a nested tree.

    @Component({
      selector: 'es-outline-tree',
      // ...
    })
    export class OutlineTreeComponent implements OnInit {
      treeControl: FlatTreeControl<FlatTreeNode>;
    
      // other code...
    
      /**
       * Recursively expand all parents of the passed node.
       */
      expandParents(node: FlatTreeNode) {
        const parent = this.getParent(node);
        this.treeControl.expand(parent);
    
        if (parent && parent.level > 0) {
          this.expandParents(parent);
        }
      }
    
      /**
       * Iterate over each node in reverse order and return the first node that has a lower level than the passed node.
       */
      getParent(node: FlatTreeNode) {
        const { treeControl } = this;
        const currentLevel = treeControl.getLevel(node);
    
        if (currentLevel < 1) {
          return null;
        }
    
        const startIndex = treeControl.dataNodes.indexOf(node) - 1;
    
        for (let i = startIndex; i >= 0; i--) {
          const currentNode = treeControl.dataNodes[i];
    
          if (treeControl.getLevel(currentNode) < currentLevel) {
            return currentNode;
          }
        }
      }
    }
    

    I'm planning to create my own FlatTreeControl (by extending Angular CDK's FlatTreeControl) and move this logic there.

    UPDATE

    I've moved the above logic to my own FlatTreeControl implementation:

    import { FlatTreeControl } from '@angular/cdk/tree';
    
    export class CustomTreeControl<T> extends FlatTreeControl<T> {
      /**
       * Recursively expand all parents of the passed node.
       */
      expandParents(node: T) {
        const parent = this.getParent(node);
        this.expand(parent);
    
        if (parent && this.getLevel(parent) > 0) {
          this.expandParents(parent);
        }
      }
    
      /**
       * Iterate over each node in reverse order and return the first node that has a lower level than the passed node.
       */
      getParent(node: T) {
        const currentLevel = this.getLevel(node);
    
        if (currentLevel < 1) {
          return null;
        }
    
        const startIndex = this.dataNodes.indexOf(node) - 1;
    
        for (let i = startIndex; i >= 0; i--) {
          const currentNode = this.dataNodes[i];
    
          if (this.getLevel(currentNode) < currentLevel) {
            return currentNode;
          }
        }
      }
    }