Dynamic Template Rendering in Angular
ngTemplateOutlet
is a directive used to dynamically render content from a template. It allows you to reuse and inject templates at runtime, providing flexibility and component composition.
In Angular, you can leverage the power of ngTemplateOutlet
and ngTemplateOutletContext
directives to dynamically render templates based on certain conditions. In this blog post, we’ll explore how to create a customizable grid that renders different templates for each item based on a property value. Let’s get started!
Prerequisites
Make sure you have the latest version of Angular CLI installed on your machine.
Setting up the Project
- Create a new Angular project by running the following command in your terminal:
ng new dynamic-grid
- Navigate to the project directory:
cd dynamic-grid
- Open the project in your preferred code editor.
Creating the Grid Component
-
Generate a new component named
grid
by running the following command:ng generate component grid
-
Open the generated
grid.component.ts
file and replace the code with the following:import { Component, ViewChild, TemplateRef } from '@angular/core'; @Component({ selector: 'app-grid', templateUrl: './grid.component.html', styleUrls: ['./grid.component.css'], }) export class GridComponent { @ViewChild('specialTemplate', { static: true }) specialTemplate!: TemplateRef<any>; @ViewChild('defaultTemplate', { static: true }) defaultTemplate!: TemplateRef<any>; items = [ { name: 'Item 1', description: 'Description 1', special: false }, { name: 'Item 2', description: 'Description 2', special: true }, { name: 'Item 3', description: 'Description 3', special: false }, ]; getItemTemplate(item: any): any { return item.special ? this.specialTemplate : this.defaultTemplate; } }
-
Next, open the
grid.component.html
file and replace the code with the following:<div class="grid-container"> <div class="grid-item" *ngFor="let item of items"> <ng-container [ngTemplateOutlet]="getItemTemplate(item)" [ngTemplateOutletContext]="{ $implicit: item }" ></ng-container> </div> </div> <ng-template #defaultTemplate let-item> <div class="default-template"> <h4>{{ item.name }}</h4> <p>{{ item.description }}</p> </div> </ng-template> <ng-template #specialTemplate let-item> <div class="special-template"> <h4>{{ item.name }}</h4> <p>{{ item.description }}</p> <p class="special-message">Special Item!</p> </div> </ng-template>
-
Finally, add the necessary styles in the
grid.component.css
file:.grid-container { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); grid-gap: 20px; } .grid-item { border: 1px solid #ccc; padding: 20px; } .default-template { background-color: #f0f0f0; } .special-template { background-color: #ffcc99; } .special-message { font-weight: bold; }
Understanding let-item
and $implicit
In the grid.component.html
file, you’ll notice that we’re using the let-item
syntax within the template definitions:
<ng-template #defaultTemplate let-item>
<!-- Default template content -->
</ng-template>
<ng-template #specialTemplate let-item>
<!-- Special template content -->
</ng-template>
The let-item
syntax allows us to define a template input variable named item
. This variable represents the current item being iterated over in the ngFor
loop. We can then access the properties of the item
object within the template.
The $implicit
property within the ngTemplateOutletContext
defines the default context for the template. By setting it to item
, we make the item
object available within the template as the default context. This allows us to directly access the item
properties without explicitly referencing item
.
Understanding @ViewChild and Static
In the component class (grid.component.ts
), we define two @ViewChild
properties to access the template references:
@ViewChild('specialTemplate', { static: true })
specialTemplate!: TemplateRef<any>;
@ViewChild('defaultTemplate', { static: true })
defaultTemplate!: TemplateRef<any>;
Here, @ViewChild
decorator allows us to query and access the template references named 'specialTemplate'
and 'defaultTemplate'
. The { static: true }
configuration option specifies that these references should be resolved at compile-time rather than at runtime.
The specialTemplate
and defaultTemplate
properties are declared with the !
operator. In TypeScript, the !
operator is the non-null assertion operator. It tells the compiler that the properties will be assigned a value at runtime and should not be considered potentially undefined or null. Since we are using @ViewChild
with static: true
, we can guarantee that the template references will be available at runtime.
The getItemTemplate
method in the component class determines which template to use based on the item.special
condition:
getItemTemplate(item: any): any {
return item.special ? this.specialTemplate : this.defaultTemplate;
}
Here, this.specialTemplate
and this.defaultTemplate
refer to the template references obtained through @ViewChild
. The $implicit
property in the ngTemplateOutletContext
provides the current item as the implicit value within the template.
By using this approach, we can dynamically switch between different templates based on the item.special
property. This allows us to customize the rendering of each item in the grid dynamically.
Running the Application
-
Save all the changes and start the Angular development server by running the command:
ng serve
-
Open your browser and navigate to
http://localhost:4200
to see the dynamic grid in action.
The grid will render a list of items, and each item will be displayed using a different template based on the special
property. If the special
property is true
, the item will be displayed with a special template that includes an additional message. Otherwise, it will use the default template.
I hope this blog post helps you understand the concept of dynamic template rendering and how it can be applied in your Angular projects. Feel free to explore further and customize the templates and styles as per your requirements.
Happy coding!