如何嵌入/投影到循环内的插槽中,并使投影内容能够访问循环变量?
假设我有一个基本组件,其中包含以下内容
<tr *ngFor="let data of items">
<td>{{data.title}}</td>
<ng-content select="[slot]"></ng-content>
</tr>
以及使用嵌入插槽"插槽"的子组件
<parent [items]="items">
<ng-container slot>
<td>{{data.category}}</td>
<td>{{data.number}}</td>
</ng-container>
</parent>
我想生成的 HTML 是
<tr>
<td>{{data.title}}</td>
<td>{{data.category}}</td>
<td>{{data.number}}</td>
</tr>
但实际发生的是,子组件中没有定义"数据",这是有道理的。有什么方法可以让它像这样工作吗?
使用TemplateRef
可以在模板级别以声明方式声明两个组件之间的模板变量。以下解决方案不完全匹配您的"槽"基础结构,但可能有助于进一步调查。
list.component.ts
import { Component, Input, ContentChild, TemplateRef } from '@angular/core';
@Component({
selector: 'list',
template: `
<tr class="box" *ngFor="let data of items">
<td>{{data.title}}</td>
<ng-template
[ngTemplateOutlet]="template"
[ngTemplateOutletContext]="{ $implicit: data }">
</ng-template>
</tr>`
})
export class ListComponent {
@Input() items;
@ContentChild(TemplateRef) template: TemplateRef;
constructor() { }
}
wrapper.component.ts
import { Component, ContentChild, TemplateRef } from '@angular/core';
@Component({
selector: 'wrapper',
template: `
<table>
<list [items]="items">
<ng-template let-data>
<td>{{data.category}}</td>
<td>{{data.number}}</td>
</ng-template>
</list>
</table>`
})
export class WrapperComponent {
items = [
{ title: 'T1', category: 'C1', number: 'N1' },
{ title: 'T2', category: 'C2', number: 'N2' },
{ title: 'T3', category: 'C3', number: 'N3' }
];
@ContentChild(TemplateRef) template: TemplateRef;
constructor() { }
}
我还创建了一个 Plunker 演示...
@dhilt的答案是一个很好的实现,但我有一种方法可以使它对命名插槽和单个插槽有用:
// list.component.ts
import { Component, Input, TemplateRef } from '@angular/core';
@Component({
selector: 'list',
template: `
<tr class="box" *ngFor="let data of items">
<td>{{data.title}}</td>
<ng-template
[ngTemplateOutlet]="template"
[ngTemplateOutletContext]="{ $implicit: data }">
</ng-template>
</tr>`
})
export class ListComponent<T extends {title: any}> {
@Input() items: T[];
@Input() template: TemplateRef<{$implicit: T}>;
constructor() { }
}
// wrapper.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'wrapper',
template: `
<table>
<list [items]="items" [template]="itemTemplate"></list>
<ng-template #itemTemplate let-data>
<td>{{data.category}}</td>
<td>{{data.number}}</td>
</ng-template>
</table>`
})
export class WrapperComponent {
items = [
{ title: 'T1', category: 'C1', number: 'N1' },
{ title: 'T2', category: 'C2', number: 'N2' },
{ title: 'T3', category: 'C3', number: 'N3' }
];
constructor() { }
}
这是 *ngTemplateOutlet
的 API 文档。甚至像*ngIf
这样的其他指令也以这种方式使用模板。