如何获得 ng-content select 过滤器来处理投影模板内容?
How can I get an ng-content select filter to work with projected template content?
我有一个用于呈现列表的 List
组件。 (好吧,我不知道,但我试图将我的问题提炼成一个易于理解的简单示例)。
List
组件的模板有一个或多个 ListItem
允许定义列表项的组件,如下所示:
<app-list>
<app-list-item text='foo'></app-list-item>
<app-list-item text='bar'></app-list-item>
</app-list>
...应呈现为:
- foo
- bar
我也有(假设)一个使用 List
组件的 Reminder
组件。 Reminder
组件有一个 deadline
属性,在此截止日期前要做的事情列表在组件的模板中定义,我们使用一个或多个 ListItem
组件之前看过:
<app-reminder deadline='Today'>
<app-list-item text='foo'></app-list-item>
<app-list-item text='bar'></app-list-item>
</app-reminder>
这应该呈现为:
Remember to do the following by Today:
- foo
- bar
List
组件很简单:
@Component({
selector: 'app-list',
template: `
<ul>
<ng-content></ng-content>
</ul>
`
})
export class ListComponent{
@ContentChildren(ListItemComponent) public readonly items: QueryList<ListItemComponent>;
}
ListItem
组件更简单:
@Component({
selector: 'app-list-item',
template: '<li>{{text}}</li>'
})
export class ListItemComponent {
@Input() public text;
}
最后,Reminder
组件也非常简单:
@Component({
selector: 'app-reminder',
template: `
<h2>Remeber to do the following by {{deadline}}</h2>
<app-list>
<ng-content></ng-content>
</app-list>
`
})
export class ReminderComponent {
@Input() public deadline: string;
}
将这些组件与上面显示的模板片段一起使用效果很好。您可以在 this StackBlitz.
中看到实际效果
现在进入问题的重点。 List
组件和Reminder
组件都使用<ng-content>
。在这两种情况下,我们真的不想将 所有 内容投影到列表中 - 只是 <app-list-item>
元素。
如果我像这样更改 Reminder
组件模板中的 <ng-content>
标记:
<ng-content select='app-list-item'></ng-content>
...那么该组件仍然有效,并且排除了其模板中的任何其他内容,这正是我们想要的。
如果我对 List
组件模板中的 <ng-content>
标记进行相同的更改,这也适用于像这样的简单模板:
<app-list>
<app-list-item text='foo'></app-list-item>
<app-list-item text='bar'></app-list-item>
<h1>EXCLUDE ME</h1>
</app-list>
但是,最后的更改(将 select
过滤器添加到 List
组件模板中的 <ng-content>
元素)停止了 Reminder
工作中的组件。提醒中没有呈现列表项。
我想这可能是因为 Reminder
组件模板渲染的 List
组件看到了 渲染的 内容(<li>
标签)而不是 模板 内容(<app-list-item>
标签)。
我在这里似乎有一个不愉快的选择 - 我可以 不 限制将由 List
组件呈现的内容类型(在这种情况下任何旧的垃圾都可能被包括在内),或者在创建其他组件时失去使用 List
组件的能力。
还是我遗漏了什么?还有其他方法吗?
我设法通过使用 ngProjectAs 解决了这个问题。
reminder.component.ts
@Component({
selector: 'app-reminder',
template: `
<h2>Remeber to do the following by {{deadline}}</h2>
<app-list>
<ng-container ngProjectAs="'app-list-item'">
<ng-content select='app-list-item'></ng-content>
</ng-container>
</app-list>
`
})
export class ReminderComponent {
@Input() public deadline: string;
}
我有一个用于呈现列表的 List
组件。 (好吧,我不知道,但我试图将我的问题提炼成一个易于理解的简单示例)。
List
组件的模板有一个或多个 ListItem
允许定义列表项的组件,如下所示:
<app-list>
<app-list-item text='foo'></app-list-item>
<app-list-item text='bar'></app-list-item>
</app-list>
...应呈现为:
- foo
- bar
我也有(假设)一个使用 List
组件的 Reminder
组件。 Reminder
组件有一个 deadline
属性,在此截止日期前要做的事情列表在组件的模板中定义,我们使用一个或多个 ListItem
组件之前看过:
<app-reminder deadline='Today'>
<app-list-item text='foo'></app-list-item>
<app-list-item text='bar'></app-list-item>
</app-reminder>
这应该呈现为:
Remember to do the following by Today:
- foo
- bar
List
组件很简单:
@Component({
selector: 'app-list',
template: `
<ul>
<ng-content></ng-content>
</ul>
`
})
export class ListComponent{
@ContentChildren(ListItemComponent) public readonly items: QueryList<ListItemComponent>;
}
ListItem
组件更简单:
@Component({
selector: 'app-list-item',
template: '<li>{{text}}</li>'
})
export class ListItemComponent {
@Input() public text;
}
最后,Reminder
组件也非常简单:
@Component({
selector: 'app-reminder',
template: `
<h2>Remeber to do the following by {{deadline}}</h2>
<app-list>
<ng-content></ng-content>
</app-list>
`
})
export class ReminderComponent {
@Input() public deadline: string;
}
将这些组件与上面显示的模板片段一起使用效果很好。您可以在 this StackBlitz.
中看到实际效果现在进入问题的重点。 List
组件和Reminder
组件都使用<ng-content>
。在这两种情况下,我们真的不想将 所有 内容投影到列表中 - 只是 <app-list-item>
元素。
如果我像这样更改 Reminder
组件模板中的 <ng-content>
标记:
<ng-content select='app-list-item'></ng-content>
...那么该组件仍然有效,并且排除了其模板中的任何其他内容,这正是我们想要的。
如果我对 List
组件模板中的 <ng-content>
标记进行相同的更改,这也适用于像这样的简单模板:
<app-list>
<app-list-item text='foo'></app-list-item>
<app-list-item text='bar'></app-list-item>
<h1>EXCLUDE ME</h1>
</app-list>
但是,最后的更改(将 select
过滤器添加到 List
组件模板中的 <ng-content>
元素)停止了 Reminder
工作中的组件。提醒中没有呈现列表项。
我想这可能是因为 Reminder
组件模板渲染的 List
组件看到了 渲染的 内容(<li>
标签)而不是 模板 内容(<app-list-item>
标签)。
我在这里似乎有一个不愉快的选择 - 我可以 不 限制将由 List
组件呈现的内容类型(在这种情况下任何旧的垃圾都可能被包括在内),或者在创建其他组件时失去使用 List
组件的能力。
还是我遗漏了什么?还有其他方法吗?
我设法通过使用 ngProjectAs 解决了这个问题。
reminder.component.ts
@Component({
selector: 'app-reminder',
template: `
<h2>Remeber to do the following by {{deadline}}</h2>
<app-list>
<ng-container ngProjectAs="'app-list-item'">
<ng-content select='app-list-item'></ng-content>
</ng-container>
</app-list>
`
})
export class ReminderComponent {
@Input() public deadline: string;
}