Search code examples
angularrecursiontreeviewparent-childangular-directive

Generate a tree view from data describing parent-child relations


Given the input data

+-------+---------+
| node  | subnode |
+-------+---------+
|   3   |    6    |
|   3   |    7    |
|   3   |    8    |
|   3   |    9    |
|   6   |    8    |
|   7   |    9    |
|   9   |    8    |
+-------+---------+

e.g. as a 2D array:

const tree = [
  [3, 6],
  [3, 7],
  [3, 8],
  [3, 9],
  [6, 8],
  [7, 9],
  [9, 8]
];

describing this tree:

3
├─ 6
│  └─ 8
├─ 7
│  └─ 9
│     └─ 8
├─ 8
└─ 9
   └─ 8

How to implement an Angular solution to show this on a web page let's say as nested <div>s like

<div id="node3" style="padding-left:2em">3<div id="node6" [...]</div>

? Illustration:

enter image description here


Solution

  • Günter Zöchbauer linked his solution which works well for simple cases where the tree view is "passive", so it is only to visualize some data as a static element.

    However, if there should be communication between the tree in the template and the component (e.g. a node has a (click) event that calls a method defined in the component), due to the fact that Günter's solution uses recursively self-contained components each node having its own directive, one might face issues:

    Handling the tree as a whole from the component is made difficult because of multiple scopes created by the repetition of the component. (- Correct me if I'm wrong.)

    That's why I needed another solution which is template-only and this way not causing the component to be replicated for each node. Here it is:

    In the .ts:

    const nodes = [{
      number: 3,
      children: [{
        number: 6,
        children: [{
          number: 8,
          children: []
        }]
      }, {
        number: 7,
        children: [{
          number: 9,
          children: [{
            number: 8,
            children: []
          }]
        }]
      }, {
        number: 8,
        children: []
      }, {
        number: 9,
        children: [{
          number: 8,
          children: []
        }]
      }]
    }];
    

    In the .html:

    <ng-template #recursion let-nodes>
      <div style="margin-left:2em" *ngFor="let node of nodes">
        {{node.number}}
        <ng-container *ngIf="node.children.length > 0">
          <ng-container *ngTemplateOutlet="recursion;
            context:{ $implicit: node.children }"></ng-container>
        </ng-container>
      </div>
    </ng-template>
    <ng-container *ngTemplateOutlet="recursion;
      context:{ $implicit: nodes }"></ng-container>
    

    P.S.: See these answers on how to convert tree to nodes.