我一直在花更多的时间试图理解以下博客文章Creating Reusable Components with NgTemplateOutlet in Angular
以上帖子的工作代码可以在stackblitz上找到。
在UsageExample
组件中,调用 card-or-list-view 组件。我非常了解提供了 items 和 mode 输入参数。
现在我不明白的是
<ng-container *cardItem="let item">
<h1>{{item.header}}</h1>
<p>{{item.content}}</p>
</ng-container>
<span *listItem="let item">
<h1>{{item.header}}</h1>
<p>{{item.content}}</p>
</span>
UsageExample
模板中的替换
<ng-container *ngSwitchCase="'card'">
<div *ngFor="let item of items" style="margin: 5px;border: black 1px solid">
<ng-container *ngTemplateOutlet="cardItemTemplate; context: {$implicit: item}">
</ng-container>
</div>
</ng-container>
<ul *ngSwitchCase="'list'">
<li *ngFor="let item of items">
<ng-container *ngTemplateOutlet="listItemTemplate; context: {$implicit: item}"></ng-container>
</li>
</ul>
在CardOrListViewComponent
组件的模板中。在CardOrListViewComponent
组件中,声明了两个指令
@ContentChild(CardItemDirective, {read: TemplateRef}) cardItemTemplate;
@ContentChild(ListItemDirective, {read: TemplateRef}) listItemTemplate;
,并且在其模板中与*ngTemplateOutlet
一起使用。
这些指令如何替换为
<ng-container *cardItem="let item">
<h1>{{item.header}}</h1>
<p>{{item.content}}</p>
</ng-container>
<span *listItem="let item">
<h1>{{item.header}}</h1>
<p>{{item.content}}</p>
</span>
在UsageExample
组件中。
*cardItem
和*listItem
如何连接到@ContentChild
组件中的两个CardOrListViewComponent
指令。他们的名字甚至都不相似。
如果有人可以给我详细说明它的工作原理,我将不胜感激。
谢谢。
答案 0 :(得分:2)
首先,Angular结构指令可以使用两种形式:
1)加糖版本
<div *ngIf="foo">bar</div>
2)减糖版本
<ng-template [ngIf]="foo">
<div>bar</div>
</ng-template>
回到您的示例:
<ng-container *cardItem="let item">
<h1>{{item.header}}</h1> sugar
<p>{{item.content}}</p>
</ng-container>
||
\/
<ng-template cardItem let-item>
<ng-container>
<h1>{{item.header}}</h1> de-sugar
<p>{{item.content}}</p>
</ng-container>
</ng-template>
第二,通常的做法是通过@ViewChild
(-dren)| @ContentChild
(-dren)装饰器引用模板中的内容。
我们可以查询与模板元素匹配的指令。 Angular始终与模板的减糖版本匹配。因此,指令:
@Directive({
selector: '[cardItem]'
})
export class CardItemDirective {}
匹配模板:
selector: '[cardItem]'
||
\/
<ng-template cardItem let-item>
如果您不希望遇到所有可能查询的情况,请遵循以下答案:
现在我们知道通过使用@ContentChild查询:
@ContentChild(CardItemDirective) cardItemTemplate;
我们获得了CardItemDirective
实例,但是我们想要获得TemplateRef
以便在*ngTemplateOutlet
中使用它。
这里是read选项的得救之地:
@ContentChild(CardItemDirective, {read: TemplateRef}) cardItemTemplate;
\/
please give us TemplateRef instance from the element
that matches CardItemDirective selector
最后,有了TemplateRef
,我们可以在ngTemplateOutlet指令的帮助下进行渲染并传递我们想要的任何上下文:
<div *ngFor="let item of items">
<ng-container *ngTemplateOutlet="cardItemTemplate; context: {$implicit: item}">