英文:
How to project repetitive content in angular component
问题
我正在构建一个树组件。数据是一个节点数组
export interface TreeNode {
id: number;
value: any;
parent: number | null;
}
...
@Input()
data: TreeNode[] = [];
我完成了绑定,一切都很好,但我希望我的组件是可定制的。
目前,我显示层次结构(表示节点的卡片和连接它们的箭头)
<!-- 简化起见 -->
<div class="tree-container">
<div *ngFor="let node of nodes" class="tree-node">{{node.value}}</div>
</div>
这适用于简单的值,但我希望可以基于值投影内容。
例如,Angular Material Table 允许以下代码
<ng-container matColumnDef="name">
<th mat-header-cell *matHeaderCellDef> Name </th>
<td mat-cell *matCellDef="let element"> {{element.name}} </td>
</ng-container>
我希望我的组件像这样实现
<tree-view [data]="data">
<div tree-node *nodes="let node"> {{node.id}} <span>Yay,现在我可以显示自定义内容,比如名字 {{node.value.name}}</span></div>
</tree-view>
我怎样才能实现这一点?
我知道内容投影的全部是 ng-content
,我知道我可以使用插槽,但我只能在单一位置使用它,而不能用于重复的内容。有什么线索吗?
注意:我正在使用 Angular 15
英文:
I'm building a tree component. where the data is an array of nodes
export interface TreeNode {
id:number;
value:any;
parent:number|null;
}
...
@Input()
data:TreeNode[] = [];
I do my binding and everything is fine, Yet, I want my component to be customizable.
For now, I'm displaying the Hierarchy (cards representing nodes, and arrows to link them)
<!-- for simplicity -->
<div class="tree-container">
<div *ngFor="let node of nodes" class="tree-node">{{node.value}}</div>
</div>
this works fine with simple values but I want it possible to project content based on the value.
For example, the Angular Material Table allows the following code
<ng-container matColumnDef="name">
<th mat-header-cell *matHeaderCellDef> Name </th>
<td mat-cell *matCellDef="let element"> {{element.name}} </td>
</ng-container>
I want my component to be implemented like that
<tree-view [data]="data">
<div tree-node *nodes="let node"> {{node.id}} <span>Yay now I can show custom stuff like name {{node.value.name}}</span></div>
</tree-view>
how can I achieve this ?
All I know about content projection is the <ng-content>
, I know that I can use slots but I can only use that with single spots not repetitive content. any clue?
> NOTE: I'm using Angular 15
答案1
得分: 0
经过一些研究和深入挖掘Angular结构性指令后,我终于找到了答案。这里的关键是使用ngTemplateOutlet
。下面是我所做的:
组件模板
<div class="tree-container">
<div *ngFor="let node of nodes" class="tree-node">
<!-- 这里可能还有其他内容 -->
<ng-container *ngTemplateOutlet="content.template; context: {$implicit: node}"></ng-container>
<!-- 这里可能还有更多其他内容 -->
</div>
</div>
content
是一个可以像下面这样创建的自定义指令
指令
@Directive({
selector: "[nodes]"
})
export class NodesDirective {
constructor(public template: TemplateRef<any>) {}
}
注意:确保在modules.ts文件中像其他组件一样声明它
组件类
在component.ts文件中添加以下属性
@ContentChild(NodesDirective) content!: NodesDirective;
就是这样。我们准备好了。
要实现这一点,可以像这样使用组件
<tree-view [data]="data">
<div *nodes="let node">
<!-- 在这里放入任何你想要的内容 -->
<h1>{{node.id}}</h1>
</div>
</tree-view>
希望这对其他人有帮助
英文:
After some research and digging deeper in Angular Structural Directives I finally found the answer myself. The trick here is to use ngTemplateOutlet
. Here's what I had to do:
Component template
<div class="tree-container">
<div *ngFor="let node of nodes" class="tree-node">
<!-- maybe some other stuff here -->
<ng-container *ngTemplateOutlet="content.template; context: {$implicit: node}"></ng-container>
<!-- maybe some more other stuff here -->
</div>
</div>
content is a custom directive that can be created like the following
Directive
@Directive({
selector: "[nodes]"
})
export class NodesDirective {
constructor(public template:TemplateRef<any>) {}
}
> NOTE: make sure to declare it like any other component in the modules.ts file
Component Class
In the component.ts file add the following attribute
@ContentChild(NodesDirective) content!: NodesDirective;
And that's it. We're ready to go.
To implement this, the component can be used like this
<tree-view [data]="data">
<div *nodes="let node">
<!-- put whatever you want here -->
<h1>{{node.id}}</h1>
</div>
</tree-view>
hope this helps someone else
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论