Angular: template inside template

jrubzjeknf

Jrubzjeknf

Posted on May 11, 2021

Angular: template inside template

You can use a template inside a template to allow a parent component to replace a wrapper around important content.

TL;DR

See this stackblitz.

Why a template inside a template?

In my case, I have a highly reusable component with two important parts, which are tightly coupled. The issue arose when a wrapper around the second part needed to be replaced.

Example

Here I want to be able to optionally replace the wrapper for part B, while being able to keep part B, like this.

Example with custom wrapper

Providing a template

For optionally replacing parts of a component, providing a template using a directive and reading it using @ContentChild is standard procedure.

The directive:

...

@Directive({
  selector: '[appWrapper]'
})
export class WrapperDirective {
  constructor(public template: TemplateRef<any>) {}
}
Enter fullscreen mode Exit fullscreen mode

Providing the template using the directive:

<subcomponent>
  <ng-template appWrapper ...>
    ...
  </ng-template>
</subcomponent>
Enter fullscreen mode Exit fullscreen mode

Reading the directive with the template inside the component:

...

export class SubComponent {
  @ContentChild(WrapperDirective, { static: true }) wrapper?: WrapperDirective;
}
Enter fullscreen mode Exit fullscreen mode

And finally rendering the template, using a fallback whenever none is provided:

<ng-container
  *ngTemplateOutlet="wrapper?.template || defaultWrapperTemplate">
</ng-container>

<ng-template #defaultWrapperTemplate>
  ...
</ng-template>
Enter fullscreen mode Exit fullscreen mode

Sweet, step 1 is done. 🚀 Time for the interesting part. 🙂

Providing the template inside the template

A template can be given context. This is an object for passing parameters to your template, which allows it to be more dynamic. For example, a component that shows a list of items could be provided a template to render each item, where the context object is the item's data.

<list>
  <ng-template listItem let-item="item">
  <div class="{{item.class}}">
    {{ item.name }}
  </div>
  </ng-template>
</list
Enter fullscreen mode Exit fullscreen mode

The cool thing is that a variable within that context object can also be a template. 👍

By passing the part B template to the wrapper template, the wrapper template can show it inside itself where it wants.

Providing the part B template to the wrapper template:

<ng-container
  *ngTemplateOutlet="wrapper?.template || defaultWrapperTemplate; context: { partBTemplate: partBTemplate }">
</ng-container>

<ng-template #partBTemplate>
  ...
</ng-template>
Enter fullscreen mode Exit fullscreen mode

And showing the part B template inside the wrapper template:

  <ng-template appWrapper let-partBTemplate="partBTemplate">
    ...

    <ng-container *ngTemplateOutlet="partBTemplate"></ng-container>
  </ng-template>
Enter fullscreen mode Exit fullscreen mode

This is all you need! 🎉

By using the template inside a template, you can easily replace a wrapper. It is very powerful and can be provided more context information to make richer wrapping templates based on information inside the component.

To see the full thing in action, see this stackblitz:

Thanks for reading!

💖 💪 🙅 🚩
jrubzjeknf
Jrubzjeknf

Posted on May 11, 2021

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related

Angular Form Array
angular Angular Form Array

November 29, 2024

Can a Solo Developer Build a SaaS App?
undefined Can a Solo Developer Build a SaaS App?

November 29, 2024

Angular's New Feature: Signals
javascript Angular's New Feature: Signals

November 29, 2024