0%

angular-ngTemplateOutlet

What’s ngTemplateOutlet?

ngTemplateOutlet is a directive that allows you to render a template dynamically.

Use Cases

一个大的页面,可能有一部分会多次被渲染,这种情况下,我们可以使用 ngTemplateOutlet 来减少重复的代码。

考虑如下需求:我们需要在一个页面上多次渲染某个产品信息,首先可以将产品信息的模板放在一个 ng-template中,并给它起一个名字叫做product, 然后通过 ngTemplateOutlet 来渲染。ngTemplateOutlet接受一个模板变量作为参数,然后将这个模板变量所指向的模板渲染到当前的位置。

1
2
3
4
5
6
7
8
9
<p>Product 1</p>
<ng-container *ngTemplateOutlet="product"/>
<p>Product 2</p>
<ng-container *ngTemplateOutlet="product"/>

<ng-template #product>
<p>Product name: computer</p>
<p>Product price: 100$</p>
</ng-template>

ngTemplateOutlet 还可以接受一个上下文参数,用来传递数据到模板中。比如上例中,我们可以把Product name和price进行参数化。

1
2
3
4
5
6
7
8
9
<p>Product 1</p>
<ng-container *ngTemplateOutlet="product; context: {name: 'computer', price: 100}"/>
<p>Product 2</p>
<ng-container *ngTemplateOutlet="product; context: {name: 'phone', price: 200}"/>

<ng-template #product let-name="name" let-price="price">
<p>Product name: {{ name }}</p>
<p>Product price: {{ price }}$</p>
</ng-template>

更进一步的,我们可以把name和price封装到一个对象中,然后传递这个对象。

1
2
3
4
5
6
7
8
9
<p>Product 1</p>
<ng-container *ngTemplateOutlet="product; context: {product: {name: 'computer', price: 100}}"/>
<p>Product 2</p>
<ng-container *ngTemplateOutlet="product; context: {product: {name: 'phone', price: 200}}"/>

<ng-template #product let-product="product">
<p>Product name: {{ product.name }}</p>
<p>Product price: {{ product.price }}$</p>
</ng-template>

渲染结果如下:

1
2
3
4
5
6
7
Product 1
Product name: computer
Product price: 100$

Product 2
Product name: phone
Product price: 200$

再进一步,我们可以将product信息放到组件中,然后通过ngTemplateOutlet来渲染。

1
2
3
4
5
6
// app.component.ts
products = [
{name: 'Book 1', price: 100},
{name: 'Book 2', price: 200},
{name: 'Book 3', price: 300},
]
1
2
3
4
5
6
7
8
9
10
<!-- app.component.html -->
<p>Product 1</p>
<ng-container *ngTemplateOutlet="product; context: {product: products[0]}"/>
<p>Product 2</p>
<ng-container *ngTemplateOutlet="product; context: {product: products[1]}"/>

<ng-template #product let-product="product">
<p>Product name: {{ product.name }}</p>
<p>Product price: {{ product.price }}$</p>
</ng-template>

再再进一步,我们可以用ngFor来循环渲染。

1
2
3
4
5
6
7
8
<ng-container *ngFor="let product of products">
<ng-container *ngTemplateOutlet="productTemplate; context: {$implicit: product}"></ng-container>
</ng-container>

<ng-template #productTemplate let-product>
<p>Product name: {{ product.name }}</p>
<p>Product price: {{ product.price }}$</p>
</ng-template>

注意,这里使用了$implicit, 这是一个特殊的关键字,表示默认的上下文参数。如果不指定上下文参数,$implicit会被用作默认的上下文参数。也就是说,let-product="product"可以简写为let-product。而$implicit后面的参数就是product. (注意,这句我已经看不懂了,有空重新整理一下。)

References

https://angular.dev/api/common/NgTemplateOutlet?tab=usage-notes