我的项目中有相当复杂的基础设施,其中包含
- 主机组件
- 宿主组件模板 (MyDir) 中使用的结构指令
- 结构指令中使用的另一个组件(MyComp)
简化版如下所示。
主机组件
@Component({
selector: 'my-app',
template: `
<table>
<tr *myDir="let item of data">
<td>{{item.text}}</td>
</tr>
</table>`
})
export class AppComponent {
data = [ { text: 'item 1' }, { text: 'item 2' } ];
}
结构性指令
import { MyComp } from './myComp';
@Directive({ selector: '[myDir][myDirOf]' })
export class MyDir implements OnInit {
private data: any;
constructor(
private templateRef: TemplateRef<any>,
private viewContainer: ViewContainerRef,
private resolver: ComponentFactoryResolver
) {
}
@Input() set myDirOf(data: any) {
this.data = data;
}
ngOnInit() {
const templateView = this.templateRef.createEmbeddedView({});
const compFactory = this.resolver.resolveComponentFactory(MyComp);
const componentRef = this.viewContainer.createComponent(
compFactory, undefined, this.viewContainer.injector, [templateView.rootNodes]
);
componentRef.instance.data = this.data;
componentRef.instance.template = this.templateRef;
}
}
结构指令的组成部分
@Component({
selector: '[my-comp]',
template: `
<tr><td>custom td</td></tr>
<ng-template *ngFor="let item of data"
[ngTemplateOutlet]="template"
[ngTemplateOutletContext]="{ $implicit: item }"
></ng-template>`
})
export class MyComp {
public template: TemplateRef<any>;
public data: any;
}
输出是
自定义 td
项目 1
项目 2
这很好,除了标记是
<table>
<div my-comp>
<tr><td>custom td</td></tr>
<tr><td>item 1</td></tr>
<tr><td>item 2</td></tr>
</div>
</table>
问题
我想<div my-comp>
从结果视图中删除中间值,或者至少将其替换为<tbody>
. 要查看我准备的Stackblitz DEMO的全貌,希望它会有所帮助......另外,很明显这个例子是人为的,但这就是我试图用最少的代码重现问题的目的。所以这个问题应该在给定的基础设施中有一个解决方案。
更新
@AlexG 找到了替换中间层的简单方法div
,tbody
并且 stackblitz 演示首先显示了一个很好的结果。tbody
但是当我尝试将它应用到本地项目时,我遇到了新问题:浏览器在表格的动态内容准备好呈现之前自行安排,这导致tbody
最终视图中有两个嵌套,这似乎与 html 规范不一致
<table>
<tbody>
<tbody my-comp>
<tr><td>custom td</td></tr>
<tr><td>item 1</td></tr>
<tr><td>item 2</td></tr>
</tbody>
</tbody>
</table>
Stackblitz 演示没有这样的问题,只有tbody my-comp
存在。但在我的本地开发环境中,完全相同的项目确实如此。所以我仍在努力寻找如何移除中间my-comp
容器的方法。
更新 2
该演示已根据@markdBC 建议的解决方案进行了更新。