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

3

8

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.

Forkey answered 13/7, 2018 at 11:54 Comment(0)
A
23

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;
      }
    }
  }
}
Atlee answered 13/7, 2018 at 14:51 Comment(6)
Your post triggered my mind to look into BaseTreeControl<T> which implements TreeControl<T> to figure out more power existing over there.Lowpressure
#52579243Frenetic
this will also trigger the siblings of a parent nodeMinerva
U rock Man... Wanna Give 100 ReputationTugman
How to expand all parent node of particular child node in nested tree control in angular 8??? I used this code with some extra fields modification stackblitz.com/angular/…Farro
It gives nodes with higher level but which are not parent of nodePoole
E
3

Thanks to Flauwekeul, a little bit simplified

import { FlatTreeControl } from '@angular/cdk/tree';

export class CustomTreeControl<T> extends FlatTreeControl<T> {
  /**
   * Iterate over each node in reverse order and expand each inferior level nodes until level 0.
   */
  expandParents(node: any) {
      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) {
              this.expand(currentNode);
              if (this.getLevel(currentNode) === 0) break;
          }
      }
  }
}
Erythrocyte answered 8/8, 2018 at 8:27 Comment(0)
P
1

Parent hierarchy can be stored in Array of numbers where each number is index of reccurent nested node. In order to expand tree on specified node I tried use previous examples, but eventually I decided make it that way:

1) ChangePath must be call every time we click on node:

changePath(node) {
if (node.level < this.nodePath.length) {
  this.nodePath.splice(node.level, this.nodePath.length - node.level);
}
this.nodePath.push(this.treeControl.dataNodes.indexOf(node));}

2) Next, when tree collapses, we must call expand of every item in nodePath (when tree collapse in is caused by delete node we dont want expand it, so last element is removed from path):

expandTreeOnSpecifiedNode(isDelete: boolean) {
  if (isDelete) {
    this.nodePath.pop();
  }
  this.nodePath.forEach(id => {
    console.log(id);
    this.treeControl.expand(this.treeControl.dataNodes[id]);
    });
  }
Prat answered 14/8, 2019 at 10:52 Comment(1)
Hierarchy can easily do with the this.nodePath.push(this.node) Thanks Man !!! GreatTugman

© 2022 - 2024 — McMap. All rights reserved.