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.

3 Answers 3

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;
      }
    }
  }
}
Sign up to request clarification or add additional context in comments.

6 Comments

Your post triggered my mind to look into BaseTreeControl<T> which implements TreeControl<T> to figure out more power existing over there.
this will also trigger the siblings of a parent node
U rock Man... Wanna Give 100 Reputation
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/…
|
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;
          }
      }
  }
}

Comments

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]);
    });
  }

1 Comment

Hierarchy can easily do with the this.nodePath.push(this.node) Thanks Man !!! Great

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.