Advanced Components in Angular

Atakan Korez
StartIt-Up
Published in
7 min readJun 25, 2023

In this blog, I am going to explain several advanced components and mechanisms in Angular that enhance flexibility, reusability, and performance.

By familiarizing yourself with these advanced components and mechanisms, you can elevate your Angular development skills and leverage the power of flexibility, reusability, and performance optimization in your applications. Let’s start!

NgContent

NgContent, or content projection in Angular allows for flexible and reusable components by projecting content from the outside into a component. It is commonly used when you want to pass content to a component dynamically.

There are also Inputand Outputoperators that serve the same purpose as the NgContent component. Input operator allows the component to receive data from the outside, while Output operator allows the component to emit events to the outside. So just data is processed with these 2 operators. When it comes to NgContent, it is used to project the contents of the component such as HTML codes and you can dynamically specify them. In this way, the flexibility of components is increased and reusability is ensured.

Let’s start with a simple example. Imagine you want to create a blog post component that includes the title, author name, date, and content. You can create a component like this:

// Blog Post Component
@Component({
selector: 'app-blog-post',
template: `
<div class="blog-post">
<h2>{{ title }}</h2>
<p class="author">Author: {{ author }}</p>
<p class="date">Date: {{ date }}</p>
<ng-content select=".blog-post-content"></ng-content>
<ng-content select=".blog-post-sidebar"></ng-content>
</div>
`,
})
export class BlogPostComponent {
@Input() title: string;
@Input() author: string;
@Input() date: string;
}

In this component, the <ng-content></ng-content> tag is used to specify where the content will be projected. When using the component, you can project the content like this:

// Home Component
@Component({
selector: 'app-home',
template:`
<h1> Home Component</h1>
<br>
<app-blog-post title="Angular is a Powerful Framework" author="Atakan KOREZ" date="June 21, 2023">
<p>Angular is a powerful framework for building modern web applications.</p>
<p>...</p>
</app-blog-post>
`
})
export class HomeComponent {
}

Output:

Multiple NgContent

Moreover, let’s provide an example of multiple ng-content usage. Suppose you want the content to be projected both below and beside the blog post title. To achieve this, you can update the component using select keyword. Also, data sent without selecting any content is received by NgContent, which does not have a selector keyword, if any. An example is below:

// Blog Post Component
@Component({
selector: 'app-blog-post',
template: `
<div class="blog-post">
<h2>{{ title }}</h2>
<p class="author">Author: {{ author }}</p>
<p class="date">Date: {{ date }}</p>
<ng-content select=".blog-post-content"></ng-content>
<ng-content select=".blog-post-sidebar"></ng-content>

<ng-content></ng-content>
</div>
`,
})
export class BlogPostComponent {
@Input() title: string;
@Input() author: string;
@Input() date: string;
}
//Home Component
@Component({
selector: 'app-home',
template:`
<h1> Home Component</h1>
<br>
<app-blog-post title="Angular is a Powerful Framework" author="Atakan KOREZ" date="June 21, 2023">
<div class="blog-post-content">
<p>Angular is a powerful framework for building modern web applications.</p>
<p>...</p>
</div>
<div class="blog-post-sidebar">
<p>Other posts by the author:</p>
<ul>
<li>...</li>
<li>...</li>
</ul>
</div>

Rest without any selector
</app-blog-post>
`
})
export class HomeComponent {
}

Output:

NgContainer

NgContainer acts as a placeholder that dynamically contains an image configured in Angular. It provides additional flexibility when creating and managing recurring elements, especially when used with constructs like *ngFor.

You can say that span element can also be used for this process and you may ask why we are using NgContainer instead of span. You are right about this, but when performance comes to the fore, NgContainer is a very performant method compared to using span. Let me try to explain this fact with the following example.

@Component({
selector: 'app-root',
template: `
<h1> App Component</h1>
<br>
<div class="mt-5">
<ul>
<span *ngFor="let product of products">
<li *ngIf="product.available">{{ product.productName }}</li>
</span>
</ul>
</div>

<div class="mt-5">
<ul>
<ng-container *ngFor="let product of products">
<li *ngIf="product.available">{{ product.productName }}</li>
</ng-container>
</ul>
</div>
`,
})
export class AppComponent {
products: any[] = [
{ productName: 'Pencil', available: true },
{ productName: 'Book', available: false },
{ productName: 'Notebook', available: true },
{ productName: 'Eraser', available: false },
{ productName: 'School Bag', available: true },
];
}

In the sample code above, the elements of Products array are listed on the page according to their available status. The same elements are listed using both span and ngContainer. So far, everything is normal, but when we examine the HTML output of the page, a difference emerges.

Output:

As can be seen from the output; When using span , 5 lielement is created without paying attention to available property, while using ngContainer only creates as many elements as the number of available elements. This makes your HTML code cleaner and more efficient.

After this critical information, I hope you will always use ngContainer from now on :)

NgTemplate

NgTemplate allows creation of sections or areas within an HTML template in Angular. There is a distinction between NgContainer and NgTemplate in terms of rendering behavior. NgTemplate needs to be explicitly called and included in the rendering process to be visible, unlike NgContainer, which is automatically rendered.

@Component({
selector: 'app-root',
template: `
<h1> App Component</h1>
<br>
<ng-container *ngTemplateOutlet="template1">
Container info...
</ng-container>
<ng-template #template1>
Template info...
</ng-template>
`,
})
export class AppComponent {
}

Output:

As you can see from the Output, the ngTemplate override the ngContainer. Also, NgContainer is often used with structures such as ngIf and ngSwitch in Angular projects. Thus, adding/removing new elements to page operations is easily handled in a controlled manner.

//ngIf example

<ng-template #myTemplate>
<p>This template is rendered conditionally.</p>
</ng-template>

<div *ngIf="showTemplate; then myTemplate"></div>

//ngSwitch example

<ng-template #templateOne>
<p>This is template one.</p>
</ng-template>

<ng-template #templateTwo>
<p>This is template two.</p>
</ng-template>

<div [ngSwitch]="value">
<div *ngSwitchCase="'A'">
<ng-container [ngTemplateOutlet]="templateOne"></ng-container>
</div>
<div *ngSwitchCase="'B'">
<ng-container [ngTemplateOutlet]="templateTwo"></ng-container>
</div>
</div>

ngTemplateOutletContext: We can provide binding data to ngTemplate using ngTemplateOutletContext. This allows us to pass values to variables inside the ngTemplate. Here’s an example:

<ng-template #myTemplate let-name="name">
<p>Hello, {{ name }}!</p>
</ng-template>

<ng-container [ngTemplateOutlet]="myTemplate" [ngTemplateOutletContext]="{ name: 'Atakan' }"></ng-container>

In the above example, ngTemplateOutletContext is used to assign the value 'Atakan' to the name variable, which is then used inside the ngTemplate. This control mechanism enables us to use ngTemplate in a more flexible and dynamic way.

Renderer2

Renderer2 is a service used to perform DOM operations in a platform-independent manner, instead of directly manipulating the DOM. Renderer2 adheres to Angular’s security model and ensures cross-platform compatibility, making it particularly useful when working with platforms like Angular Universal. Here are some advantages of using Renderer2 instead of JS or JQuery for manipulating the DOM:

  • Platform Independence: Renderer2 provides a platform-specific backend for performing DOM operations, allowing Angular applications to work on different platforms.
  • Security: Renderer2 operates in compliance with Angular’s security model. Instead of direct DOM manipulation, Renderer2 allows for secure DOM operations.
  • Performance and Optimization: Renderer2 optimizes the change detection mechanism of Angular and applies changes more efficiently. Changes can be batched within a single update cycle for improved performance.

Here’s an example:

@Component({
selector: 'app-example',
template: `
<button (click)="changeColor()">Change Color</button>
`,
})
export class ExampleComponent {
constructor(private elementRef: ElementRef, private renderer: Renderer2) {}

changeColor() {
const button = this.elementRef.nativeElement.querySelector('button');
this.renderer.setStyle(button, 'background-color', 'blue');
this.renderer.setStyle(button, 'color', 'white');
}
}

In the above example, we have created a component named ExampleComponent. Renderer2 is injected into the component’s constructor. The changeColor() method changes the background color and text color of the button. DOM manipulation is performed through Renderer2, allowing for secure assignment of style properties. So, using Renderer2 ensures that Angular applications are more secure, portable, and performant.

Conclusion

In this blog, I explained advanced components and mechanisms in Angular that enhance flexibility, reusability, and performance. By leveraging these components and mechanisms, developers can achieve flexible and reusable components, clean and efficient code, conditional rendering, and secure DOM operations, resulting in enhanced Angular applications.

By incorporating these advanced components and mechanisms into your Angular projects, you can unlock new levels of flexibility, reusability, and performance optimization. Embrace the power of NGContent, NgContainer, NgTemplate, and Renderer2 to build robust and dynamic applications with ease.

If you found this blog post helpful, please give it a clap. Thanks for reading…

--

--

Atakan Korez
StartIt-Up

Senior Software Engineer | .NET | C# | SQL | Full-Stack | Angular 2+ | Azure | DevOps. Find me at linkedin.com/in/atakankorez/