注意-我意识到可以不使用内容投影而更轻松地完成此示例。我将其用作一个非常简化的示例。
可以说我有以下组件,其中列出了两个不同元素中的名称:
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-name-list',
templateUrl: `
<div class='large'>
<h1>Large Names</h1>
<ng-content select="large"></ng-content>
</div>
<div class='small'>
<h1>Small Names</h1>
<ng-content select="small"></ng-content>
</div>
`,
styleUrls: ['./name-list.component.css']
})
export class TestNgContentComponent {
constructor() { }
}
然后我可以从具有两个名称列表的模板中调用此组件,如下所示:
<app-names-list>
<h1 ngProjectAs="large" *ngFor="let n of names">{{ n }}</h1>
<h2 ngProjectAs="small" *ngFor="let n of names">{{ n }}</h2>
</app-names-list>
请注意,相同的数据用于两个名称列表。是否可以用包含两者的组件替换传递的h1和h2标签,并将它们投影到父对象?例如。像这样的东西:
@Component({
selector: 'app-name',
template: `
<h1 ngProjectAs="large">{{name}}</h1>
<h2 ngProjectAs="small">{{name}}</h2>
`,
styles: [`h1 { font-family: Lato; }`]
})
export class HelloComponent {
@Input() name: string;
}
,然后将模板修改为:
<app-names-list>
<app-name *ngFor="let n of names" [name]="n"></app-name>
</app-names-list>
一旦将ngProjectAs
指令嵌入app-name
模板中,该指令将不再起作用。是否可以从子组件中进行这样的投影?
答案 0 :(得分:2)
这是我的方法:
我将header tags
包裹在ng-template
中,以便可以将其附加作为嵌入式视图附加到ng-container
上。
您可以了解有关embedded
和host
视图here的更多信息。
@Component({
selector: 'app-name',
template: `
<ng-template #large>
<h1>{{name}}</h1>
</ng-template>
<ng-template #small>
<h2>{{name}}</h2>
</ng-template>
`,
styles: [`h1 { font-family: Lato; }`]
})
export class HelloComponent {
@Input() name: string;
@ViewChild('large', { static: true, read: TemplateRef }) large: TemplateRef<any>;
@ViewChild('small', { static: true, read: TemplateRef }) small: TemplateRef<any>;
}
在这里,我将ng-content
替换为ng-container
,以便可以附加嵌入的视图。
@Component({
selector: 'app-name-list',
template: `
<div class='large'>
<h1>Large Names</h1>
<ng-container #large></ng-container>
</div>
<ng-container #foo></ng-container>
<div class='small'>
<h1>Small Names</h1>
<ng-container #small></ng-container>
</div>
`,
})
export class TestNgContentComponent {
@ContentChildren(HelloComponent, { read: HelloComponent }) children: QueryList<HelloComponent>;
@ViewChild('large', { static: true, read: ViewContainerRef }) largeNamesContainer: ViewContainerRef;
@ViewChild('small', { static: true, read: ViewContainerRef }) smallNamesContainer: ViewContainerRef;
constructor() { }
ngAfterContentInit () {
this.populateView();
}
private populateView () {
this.largeNamesContainer.clear();
this.smallNamesContainer.clear();
this.children.forEach(child => {
this.largeNamesContainer.createEmbeddedView(child.large);
this.smallNamesContainer.createEmbeddedView(child.small);
});
}
}