Use component in itself recursively to create a tree

using ng-template is the best solution to solve recursive DOM problems.

@Component({
  selector: 'tree-node',
   template: `
     <ng-container *ngTemplateOutlet="tree;context:{node:node}">
     </ng-container>

     <ng-template #tree let-node="node">
       <div>{{node.name}}</div>
       <ul *ngIf="node.children && node.children.length > 0">
         <ng-container *ngFor="let child of node.children">
           <li>
             <ng-container *ngTemplateOutlet="tree;context:{node:child}">
             </ng-container>
           </li>
         </ng-container>
       </ul>
     </ng-template>
   `
})
export class TreeNode {
    @Input() node;
}

No needs to add the component to directives: [] in its @Component().

@Component({
  selector: 'my-app',
  template: `
    <div>
      <h2>Hello {{name}}</h2>
      <tree-node [node]="node"></tree-node>
    </div>
  `
})
export class App {

  node = {
    name: 'root', children: [
      { name: 'a', children: [] },
      {
        name: 'b', children: [
          { name: 'b-1', children: [] },
          {
            name: 'b-2', children: [
              { name: 'b-2-1', children: [] },
              { name: 'b-2-2', children: [] },
              { name: 'b-2-3', children: [] }
            ]
          }
        ]
      },
      {
        name: 'c', children: [
          { name: 'c-1', children: [] },
          { name: 'c-2', children: [] }
        ]
      },
    ]
  };

}

Output:

  • root
    • a
    • b
      • b-1
      • b-2
        • b-2-1
        • b-2-2
        • b-2-3
    • c
      • c-1
      • c-2

HTML:

<tree-node>
    <div>root</div>
    <ul>
        <li>
            <div>a</div>
        </li>
        <li>
            <div>b</div>
            <ul>
                <li>
                    <div>b-1</div>
                </li>
                <li>
                    <div>b-2</div>
                    <ul>
                        <li>
                            <div>b-2-1</div>
                        </li>
                        <li>
                            <div>b-2-2</div>
                        </li>
                        <li>
                            <div>b-2-3</div>
                        </li>
                    </ul>
                </li>
            </ul>
        </li>
        <li>
            <div>c</div>
            <ul>
                <li>
                    <div>c-1</div>
                </li>
                <li>
                    <div>c-2</div>
                </li>
            </ul>
        </li>
    </ul>
</tree-node>

update

forwardRef() isn't required anymore because directives was moved to NgModule.declarations and therefore recursive components don't need to be registered on themselves as directives anymore.

Angular 4.x.x Plunker example

original

That supported. You just need to add the component to directives: [] in its @Component() decorator. Because the decorator comes before the class and classes can't be referenced before they are declared forwardRef() is necessary.

import {Component, forwardRef, Input} from '@angular/core'

@Component({
  selector: 'tree-node',
  template: `
  <div>{{node.name}}</div>
  <ul>
    <li *ngFor="let node of node.children">
      <tree-node  [node]="node"></tree-node>
    </li>
  </ul>
`
})
export class TreeNode {
  @Input() node;
}
@Component({
  selector: 'my-app',
  template: `
    <div>
      <h2>Hello {{name}}</h2>
      <tree-node [node]="node"></tree-node>
    </div>
  `,
  directives: [TreeNode]
})
export class App {
  constructor() {
    this.name = 'Angular2 (Release Candidate!)'
  }

  node = {name: 'root', children: [
    {name: 'a', children: []},
    {name: 'b', children: []},
    {name: 'c', children: [
      {name: 'd', children: []},
      {name: 'e', children: []},
      {name: 'f', children: []},
     ]},
  ]};  
}

Angular 2.0.0-beta.x Plunker example

See also Inject parent component of the same type as child component


Angular 4 example of recursive components: https://plnkr.co/edit/IrW82ye4NKK8cYEPxsFc?p=preview

Excerpt from linked example:

//our root app component
import {Component, NgModule, VERSION, Input} from '@angular/core'
import {BrowserModule} from '@angular/platform-browser'

@Component({
  selector: 'tree-node',
  template: `
  <div>{{node.name}}</div>
  <ul>
    <li *ngFor="let node of node.children">
      <tree-node  [node]="node"></tree-node>
    </li>
  </ul>
`
})
export class TreeNode {
  @Input() node;
}

@Component({
  selector: 'my-app',
  providers: [],
  template: `
    <div>
      <h2>Hello {{name}}</h2>
      <tree-node [node]="node"></tree-node>
    </div>
  `
})
export class App {
  constructor() {
    this.name = 'Angular2 (Release Candidate!)'
  }

  node = {name: 'root', children: [
    {name: 'a', children: []},
    {name: 'b', children: []},
    {name: 'c', children: [
      {name: 'd', children: []},
      {name: 'e', children: []},
      {name: 'f', children: []},
     ]},
  ]};  
}

@NgModule({
  imports: [ BrowserModule ],
  declarations: [ App, TreeNode ],
  bootstrap: [ App ]
})
export class AppModule {}

This answer is a community wiki because the example link was copied from Günter Zöchbauer's answer. I included the code in the question body to avoid link rot.