SoFunction
Updated on 2025-04-04

Two ways to pass templates to components in Angular

Recently I am writing a date selector component. In order to meet various possible future needs, I need to be able to highly customize the style of the component. To achieve this, it is necessary to be able to control the content to be displayed in each date grid outside the date selector component, such as marking holidays or the like. At this time, some templates of the component need to be provided by the caller.

In React, this requirement is quite simple, just implement onedate => Element Such a function would be great, but Angular templates are pure templates and require some special concepts to achieve this function.

The first method <ng-content>

<ng-content> This tag has not been officially documented until the time of writing this article, and there is not even a placeholder. But this does not hinder our use. enthusiastic foreign netizens have summarized the characteristics and functions of <ng-content> at this stage.

Basic usage

<!--  -->
<div>
  hello
  <ng-content></ng-content>
</div>

Suppose we have a component mentioned above and call it like this:

<wrapper>
  <span> World </span>
</wrapper>

Then the final rendering result will be like this:

<div>
  hello
  <span> World </span>
</div>

It seems that a very simple replacement has occurred, but if multiple replacements appear in Wrapper <ng-content>Will there be multiple <span> World </span>? The answer is no.<ng-content>The essence of this is to move elements and will not automatically create incoming templates, so even if you use ngFor to trap it<ng-content> There will be no many <span> World </span>s. If the incoming is a custom component, these components will only be instantiated once.

Advanced usage

Of course, if<ng-content> The function is just like this, it looks too useless.<ng-content>You can specify a selector that can capture corresponding direct child elements. For example:

<!--  -->
<div>
  hello
  <ng-content></ng-content>
  <hr/>
  <ng-content select="span"></ng-content>
</div>

Then use it like this:

<wrapper>
  <span> World </span>
  2333
</wrapper>

The final rendering result will be like this:

<div>
  hello
  2333
  <hr/>
  <span> World </span>
</div>

In addition to settingsng-content In addition to the select attribute of the tag, you can also use the ngProjectAs attribute on the child element, which allows this element to be captured by the ng-content specified in the parent element. For example:

<wrapper>
  <div ngProjectAs="span"> World </div>
  2333
</wrapper>

The template passed in this time becomes a div, but because ngProjectAs is set, "World" will appear below the dividing line.

The second method NgTemplateOutlet instruction

useng-content It can indeed have the effect of passing in templates, but there is a very fatal problem, that is, it cannot pass data into the incoming templates. In order to pass data into the incoming template, the NgTemplateOutlet directive needs to be used.

Basic use

This directive can be used to instantiate a TemplateRef object at the specified location of the template. At the same time, a data object can be passed in during the instantiation process. TemplateRef can be created through the ng-template tag, for example:

@Component({
 selector: 'ng-template-outlet-example',
 template: `
  <ng-container *ngTemplateOutlet="name; context: myContext"></ng-container>

  <ng-template #name let-name="data"><span>Hello {{name}}!</span></ng-template>
`
})
class NgTemplateOutletExample {
 myContext = {data: 'World'};
}

ng-container is a virtual element. On this element we use an NgTemplateOutlet directive, specifying the ng-template named name to instantiate below. At the same time, the myContext object is passed in as the instantiated data context, so the "Hello World!" will eventually be displayed. It is worth noting that the way to obtain the transmitted data context in ng-template:let-variableName='key'

Advanced use

Next, we need to implement the requirements mentioned at the beginning of this article, and pass in the template outside the component. Let’s take the example above as an example. Because the template needs to be passed in from the outside world as a sub-content, we need to manually capture the template. If you need it here, you need to use ContentChild:

@Component({
 selector: 'wrapper',
 template: `
  <ng-container *ngTemplateOutlet="name; context: myContext"></ng-container>
`
})
class NgTemplateOutletExample {
 @ContentChild(TemplateRef) name: TemplateRef<any>;
 myContext = {data: 'World'};
}

It is such a simple change that allows our components to accept templates from the outside world. Let's try:

<wrapper>
  <ng-template let-value="data">
    <span>Hello {{value}}!</span>
  </ng-template>
</wrapper>

Summarize

The above are two methods of passing templates to components in Angular, where<ng-content>Tags can more conveniently control the position of incoming templates in the DOM, while NgTemplateOutlet can pass rendering data to incoming templates. The combination of the two can have a good effect.

The above are the two methods of Angular passing templates to components introduced by the editor. I hope it will be helpful to everyone. If you have any questions, please leave me a message and the editor will reply to everyone in time. Thank you very much for your support for my website!