Advanced Components in Angular
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 Input
and Output
operators 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 li
element 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…