Handle Recursive Inner Child Elements in Angular

First things first

npm i -g @angular/cli ng new recursive-child --defaults --minimal --inlineStyle

Code

// src\app\app.component.ts

...
export class AppComponent {
replies = [
{
id: 1,
value: 'Lorem'
},
{
id: 2,
value: 'Ipsum'
},
{
id: 3,
value: 'Dolor'
},
{
id: 4,
value: 'Sit'
}
]
}
// src\app\app.component.ts

...
template: `
<ul>
<li *ngFor="let reply of replies"><b>{{reply.id}}:</b> {{reply.value}}</li>
</ul>
`,
styles: [
"ul { list-style: none }"
]
...
// src\app\app.component.ts

...
replies = [
{
id: 1,
value: 'Lorem',
children: [
{
id: 1.1,
value: 'consectetur',
children: [
{
id: '1.1.1',
value: 'adipiscing '
}
]
}
]
},
{
id: 2,
value: 'Ipsum'
},
{
id: 3,
value: 'Dolor',
children: [
{
id: 3.1,
value: 'eiusmod'
},
{
id: 3.2,
value: 'labore',
children: [
{
id: '3.2.1',
value: 'aliqua'
}
]
}
]
},
{
id: 4,
value: 'Sit'
}
]
// src\app\app.component.ts

...
template: `
<ul>
<li *ngFor="let reply of replies">
<b>{{ reply.id }}:</b> {{ reply.value }}
<ul *ngIf="reply.children">
<li *ngFor="let childReply of reply.children">
<b>{{ childReply.id }}:</b> {{ childReply.value }}
</li>
</ul>
</li>
</ul>
`,
  1. We are looping through all replies
  2. Next, in <li> we are checking if that reply has children
  3. If so, we are creating child list and showing the id and value

1. ng-template & ng-container

<ng-template #templateName> some content </ng-template>
// example

@Component({
selector: 'ng-template-outlet-example',
template: `
<ng-container *ngTemplateOutlet="eng; context: myContext"></ng-container>
<ng-template #eng let-name><span>Hello {{name}}!</span></ng-template>
`
})
export class NgTemplateOutletExample {
myContext = {$implicit: 'World'};
}
  1. We created a <ng-template> with #eng as TemplateRef. This template also prints the name from it's context object, thanks to let-name.
  2. We created a <ng-container>. We asked it to render eng template with myContext as context.
  3. We created myContext class property, which has only one key-value pair: {$implicit: 'World'}. Thanks to $implicit, it's value is set as default value in <ng-template>
  4. <ng-template> uses let-name, accesses default value from myContext and assigns it in name and it prints
// src\app\app.component.ts

...
template: `
<ng-container
*ngTemplateOutlet="replyThread; context: { $implicit: replies }"
></ng-container>
<ng-template #replyThread let-childReplies>
<ul>
<li *ngFor="let reply of childReplies">
<b>{{ reply.id }}:</b> {{ reply.value }}
<ng-container *ngIf="reply.children">
<ng-container
*ngTemplateOutlet="
replyThread;
context: { $implicit: reply.children }
"
></ng-container>
</ng-container>
</li>
</ul>
</ng-template>
`,
...
  1. We are creating a <ng-container>. And we are asking it to render replyThread template with { $implicit: replies } as context.
  2. Next, we are creating a <ng-template> with replyThread as TemplateRef. We are also using let-childReplies, so that inner code can use childReplies.
  3. Now, in <ng-template>, first we are looping through all childReplies.
  4. Then, we are checking, if any reply of childReplies has children.
  5. If yes, then we are repeating step 1, but with { $implicit: reply.children } as context.

2. A reply Component

ng g c reply
// src\app\reply\reply.component.ts

import { Component, OnInit, Input } from "@angular/core";

@Component({
selector: "app-reply",
template: `
<ul>
<li *ngFor="let reply of replies">
<b>{{ reply.id }}:</b> {{ reply.value }}
</li>
</ul>
`,
styles: [],
})
export class ReplyComponent implements OnInit {
@Input() replies: { id: string | number; value: string; children: any[] }[];

constructor() {}

ngOnInit(): void {}
}
  1. We are accepting replies as @Input()
  2. We are looping through all the replies and printing id and value in ul > li
// src\app\app.component.ts

...
template: `
<app-reply [replies]="replies"></app-reply>
`,
...
// src\app\reply\reply.component.ts

...
template: `
<ul>
<li *ngFor="let reply of replies">
<b>{{ reply.id }}:</b> {{ reply.value }}
<!-- 🚨 Note the usage of component inside same component -->
<app-reply *ngIf="reply.children" [replies]="reply.children"></app-reply>
</li>
</ul>
`,
...
https://github.com/shhdharmen/recursive-child

Thank you,

Photo by Cata on Unsplash

--

--

--

Developer @ solvative.com, Blogs @ http://blog.shhdharmen.me, Open source @ http://github.com/shhdharmen, Writer @ indepth.dev

Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

SFrame.js: end to end encryption for WebRTC

Joi validate create and update operations with only one schema

Joi schema

Some Tips and Tricks to Become a Good Programmer

Understanding Fragments in React

React Native + Redux (Part 2)

Apache Struts 2: Redirecting to a link and another Action

Fun with Java Script

Everything You Need To Know About Hoisting in JavaScript

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Dharmen Shah

Dharmen Shah

Developer @ solvative.com, Blogs @ http://blog.shhdharmen.me, Open source @ http://github.com/shhdharmen, Writer @ indepth.dev

More from Medium

Angular Promise Function

HTTP get request example with angular,

What is Angular?

Angular — ellen’s note