Recently, I was looking at a training program and saw the NgTemplateOutlet structural instruction, but I didn’t know how to use it before, so I went to the official website to search for the API (the official website link is here).
I don’t know what the context object is, and I don’t know what the let variable is. After a day of flipping through documents and taking notes, I finally figured out what it was. For those of you who didn’t, refer to my previous article: Angular Learning: Understanding Let-variables
In this article, I’ll just show you how to use NgTemplateOutlet and where to use it.
Method of use
The API, according to the website, looks like this:
Insert an embedded view based on a pre-prepared TemplateRef.
Make the host element of the NgTemplateOutlet an inline view generated from a pre-defined reference to the templateRef template. The host element, whatever it is, is not rendered.
Let’s change the example from the official website (because I don’t understand the lives on the official website) :
@Component({
selector: 'ng-template-outlet-example'.template: `
Hello
Hello {{name}}!
My name is
LeBron {{person}}!
`
})
export class NgTemplateOutletExample {
myContext = {$implicit: 'World'.lastName: 'James'};
}
Copy the code
A host element can use the structural directive ngTemplateOutlet to make itself an embedded view generated by any
template. And you can give it a context object. Then we can use let-variables in this template, which is a template input variable to get the value in the context object. This template is more flexible.
Application scenarios
The Pagination component of the ng-Zorro framework is similar (link to website). If we are not satisfied with the default style or structure of the previous and next pages and want to adjust it ourselves, we can provide an Input property (defined by @input) to receive a template and provide the necessary properties or methods for it. In this way, we can reuse components without modifying their source code.
Demo
Let’s define a child component, HeroDisplayCard, the display interface for the character
@Component({
selector:'app-hero-display-card'.template:< span style =" box-sizing: border-box! Important; word-wrap: break-word! Important; word-wrap: break-word! Important; HeroesList "> < p [style] =" {textAlign: 'center'} "> character id: {{h.i d}} - character name: {{h.n ame}} - character attributes: {{h.f eatures}} < / p > < / li > < / ul > `.styles: [`.hero-card-box{ width: 600px; margin: 10px auto; } .hero-card-item{ list-style: none; } `]})export class HeroDisplayCard {
public heroesList = [
{id:'013'.name:'clock from'.features:'rock'},
{id:'061'.name:'smoke Fei'.features:'fire'},
{id:'022'.name:'Diona'.features:'ice'},
{id:'004'.name:'Noelle'.features:'rock']}},Copy the code
Then introduce this component into a parent component:
@Component({
selector:'app-templateoutlet-app-demo'.template:`
`
})
export class TemplateOutletAppDemoComponent {}
Copy the code
Run the code and it looks like this:
I think the li style is too ugly, and the order is not quite right. I want to put the character attributes before the character name. In this case, it would be difficult to change the style simply by using the input property, and we would need to define a lot of variables for the user to choose from, which would be a bit of a loss. So why don’t we just provide a template to the user, we just need to provide the necessary data. The style, the layout these freedom to the user.
So for the child HeroDisplayCard we can do this:
@Component({
selector:'app-hero-display-card'.template:'<h2 [style]="{textAlign:'center'}"> </h2> <ul class="hero-card-box"> <ng-container *ngFor="let h of heroesList"> <! <li class="hero-card-item" *ngIf="! CardItemTemplate "> < p [style] =" {textAlign: 'center'} "> character id: {{h.i d}} - character name: {{h.n ame}} - character attributes: {{h.features}} </p> </li> <! <ng-container *ngIf="cardItemTemplate"> <! < container *ngIf="cardItemTemplate"> <! -- Set the context object of the custom template to h --> <ng-container *ngTemplateOutlet="cardItemTemplate; context:h"></ng-container> </ng-container> </ng-container> </ul> `.styles: [/ / ellipsis]
})
export class HeroDisplayCard {
@Input() cardItemTemplate:TemplateRef<any>;
public heroesList = [ / / ellipsis]
}
Copy the code
Then we pass in our custom template in the parent component:
@Component({
selector:'app-templateoutlet-app-demo'.template:` <app-hero-display-card [cardItemTemplate]="myCardTemplate"></app-hero-display-card> <! <ng-template #myCardTemplate let-id="id" let-name="name" let-features="features"> <li Class = "hero - card - custom - item" > < p > character id: < span > {{id}} < / span > < / p > < p > character attributes: < span > {{the features}} < / span > < / p > < p > character name: <span>{{name}}</span></p> </li> </ng-template> `.styles: [// Write the style of the custom template here
`.hero-card-custom-item{ width: 100%; height: 35px; border: 1px solid #999999; border-radius: 5px; display: flex; justify-content:space-around; align-items: center; margin: 10px 0; } .hero-card-custom-item p { width: 30%; margin: 0; font-size: 20px; color: #666666; } .hero-card-custom-item p span { color: red; } `]})export class TemplateOutletAppDemoComponent {}
Copy the code
Then run it and it looks like this (still ugly) :
conclusion
Using the NgTemplateOutlet structural directive allows us to enhance the encapsulation of our child components and avoid the need to define a large number of input properties that can make the parent component’s template look bloated.