DEV Community

khizerrehandev
khizerrehandev

Posted on • Edited on

Understanding ng-template, ng-container, *ngTemplateOutlet directive in Angular (ng-πŸš€)

Angular Template Fundamentals

It's always valuable to understand a few technical jargons and understand how multiple components can be combined or put together to build larger applications that have complex functionalities.

What is EmbeddedView

As per Angular docs states "An embedded view can be referenced from a component other than the hosting component whose template defines it..."

A embedded view is basically a way of dynamically showing a template of another component within another component's template OR It it allows to create a template as a part of host component's template.

I am sure you might be confused at this point let's divide into 2 parts:

part-1: "within another component's template..."

Let's have 2 components Child-A and Child-B as separate angular components (ts/html/css|scss). So In order to create embedded view (dynamic creation) of a component template conditionally it can be achieved via structural directive.

So It is as simple to embed a template or dynamically create template view into another component template e.g Parent component template. Yes that's it πŸŽˆπŸŽ‰πŸ₯³

  • Template defined as part of another component.


<!-- Parent component template -->
<section>
  <header>Header</header>
</div>

<!-- Content Section -->
<section class="content">
  <app-child-A *ngIf="<condition-1>"></app-child-A>
  <app-child-B *ngIf="<condition-2>"></app-child-B>
</div>


Enter fullscreen mode Exit fullscreen mode

part-2: "template as part of host" template..."

  • Defined independently by a TemplateRef with in Host component.


<!-- Parent component template -->
<section>
  <header>Header</header>
<ng-container *ngTemplateOutlet="logoTpl"></ng-container>
</div>

<!-- Content Section -->
<section class="content">
    ...
</div>

<footer>
  <ng-container *ngTemplateOutlet="logoTpl"></ng-container>
</footer>


<!-- Embedded View Template -->
<ng-template #logoTpl>
  <img src="path" alt="logo image" />
</ng-template>


Enter fullscreen mode Exit fullscreen mode

Here it was defined as part of Hosting component template using "TemplateRef" variable without being tied to specific another component template.

ℹ️

  • TemplateRef is denoted via #pound/hash sign on ```html


...
</ng-template

- TemplateRef can be accessed via ViewChild and can be programatically create embedded view with in Host container ref. [Playground Stackblitz](https://stackblitz.com/edit/angular-create-embedded-view-6gfcn7b?file=src%2Fapp%2Fapp.component.ts)

Embedded View basically promotes building complex and interactive features by composing smaller, reusable building blocks by referencing **reusable** templates defined either in host component or tied to separate component.

Here's a basic example to illustrate the concept:

- [`*ngFor`](https://angular.io/api/core/EmbeddedViewRef#usage-notes)

```html


Count: {{items.length}}
<ul>
  <li *ngFor="let  item of items">{{item}}</li>
</ul>


Enter fullscreen mode Exit fullscreen mode

The *ngFor directive represents an embedded view, and it is responsible for generating and managing the repeated HTML markup.



<container-element [ngSwitch]="switch_expression">
  <!-- the same view can be shown in more than one case -->
  <some-element *ngSwitchCase="match_expression_1">...</some-element>
  <some-element *ngSwitchCase="match_expression_2">...</some-element>
...
  <!--default case when there are no matches -->
  <some-element *ngSwitchDefault>...</some-element>
</container-element>


Enter fullscreen mode Exit fullscreen mode

The *ngSwitchCase directive represents an embedded view, and it is responsible for generating and managing the dynamic HTML markup.

Advantages of embedded view:

  • Flexibility for customisation by passing context data
  • Reusability to avoid code duplication
  • Code Clarity/Clean helps to keep template clear, concise
  • Easy to Maintain from future perspective.
  • Structural directives can play role to show/hide based on conditional rendering to make customised UI based on conditions

ng-template

Have you heard about template tag in HTML5. The purpose of tag is if you have some HTML code you want to use repeatedly but not rendered until you ask for it to to create view.

Similarly Angular provides powerful built in tag exported from CommonModule called ng-template

Think of ng-template as a blueprint for creating something. It's like a mold or class from OOP perspective that you can use to make multiple copies of an object within a document.

It act as placeholder where static/dynamic reusable HTML markup can placed and based on context passed to ng-template dynamic content + based on condition blueprint copies view can be created.

  • Static content ```html

Success message!


Default message.



- Passing context to ng-template
```ts


const data = {
 name: 'Khizer'
 title: 'Web Developer{% raw %}`
}
```

```html
<!-- Syntax-1 -->
<ng-container *ngTemplateOutlet="customTpl; context: {$implicit: data}"></ng-container>

<!-- Syntax-2 -->
<ng-template [ngTemplateOutlet]="customTpl" [ngTemplateOutletContext]="{$implicit: data}"

<ng-template #customTpl let-data>
  <div>{{ data.name }}</div>
  <p>{{ data.title }}</p>
</ng-template>

```

**ng-container**

A special element that is provided by Angular to group or bind HTML markup together. Think it as **Imaginary box/container** which groups HTML element together

**Key Benefits/Usages of ng-container**

- **Grouping Element:** in order to apply structural directives `ngIf`, `ngFor`, or `ngSwitch` in order to render content based on conditions + It doesn't Produce any **extra** DOM element HTML markup DOM which serve the best purpose and hold things togther without adding something and creating chaos in DOM

- **Multiple directives can be applied:**

⚠️ _Angular docs: Multiple structural directives cannot be used on the same element [Read here](https://angular.io/api/core/ng-container#combination-of-multiple-structural-directives). If you need to take advantage of more than **one** structural directive, it is advised to use `<ng-container>` per structural directive._

Note: nesting containers are used to apply conditional logic

```html
<div *ngFor="let group of groups">
  ...
  <ng-container *ngIf="<condition-1>">
      <ng-container *ngFor="<condition-2>">
         <ng-container *ngFor="<condition-3>">
          ... These nesting conditions can be applied ... 
         </ng-container>
      </ng-container>
  </ng-container>
</div>
```

- **Creating container scope:**
`ng-container` creates a new variable scope, meaning any variables or context defined within an `ng-container` are only accessible within that container or immediate children HTML markup. Think like a functional scope
when you declare/define a function anything defined there is respect to that scope so Global scope variables can be accessed inside but not the **vice-versa**

Here's an example usage of `ng-container`:

```html
<div *ngIf="condition">
  <ng-container *ngFor="let val of values">
    <p>{{ val }}</p>
  </ng-container>
</div>
```

**ngTemplateOutlet**

`ngTemplateOutlet` is a directive used to render the content of an `ng-template` at a specific location in the template. It allows you to dynamically render a template referenced by its template variable or template reference.

**1. Template declaration/definition:**

_Note:_ By default it is not rendered you need to explicitly need to inject or render the dynamic embedded view through multiple ways in order to create and stamp HTML markup in DOM.

```html
<ng-template #myTemplate>
  <p>I am a template and can be rendered any place!</p>
</ng-template>
```
**Template Rendering**

In order to render the template, you use the `ngTemplateOutlet` directive on an element within the template where you want the content to be rendered.
You reference the `ng-template` by its template reference `#variable`

```html
<div [ngTemplateOutlet]="myTemplate"></div>

or

<ng-container [ngTemplateOutlet]="myTemplate"></ng-container>
```

**2. Pass Contextual data:** You can also pass contextual data to the template being rendered by using the 

You can even pass context to template to the template by using `[ngTemplateOutletContext]` input. It allows you to provide additional variables or data that can be accessed within the template.

`ngTemplateOutlet`.It provides a powerful mechanism for creating flexible and customizable components and enhancing code modularity and reusability.

**4. Repeating/Reusability:** You can use to create embedded view multiple times e.g 5 instance are created 

```html
<ng-container *ngTemplateOutlet="repeatTpl"></ng-container>
<ng-container *ngTemplateOutlet="repeatTpl"></ng-container>
<ng-container *ngTemplateOutlet="repeatTpl"></ng-container>
<ng-container *ngTemplateOutlet="repeatTpl"></ng-container>
<ng-container *ngTemplateOutlet="repeatTpl"></ng-container>

<ng-template #repeatTpl>
 <h2> Repeatable content </h2>
</ng-template>

```

I am sure there is something you have learned tutorial and understanding these complex terms. Which i am sure it will be clear and hopefully will help you to build more modular templates and making your code much less cluttered. 

Let me know your thoughts via comments and feedback. πŸ’¬

Happy coding and Happy Learning! πŸš€πŸš€
Enter fullscreen mode Exit fullscreen mode

Top comments (0)