gpt4 book ai didi

javascript - 在 Angular 结构指令中使用动态组件会产生额外的 HTML 标签。如何去除或更换它?

转载 作者:行者123 更新时间:2023-11-30 13:48:22 24 4
gpt4 key购买 nike

我的项目中有相当复杂的基础设施,其中包含

  • 宿主组件
  • 宿主组件模板(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;
}

输出是

custom td
item 1
item 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>从结果 View 或至少将其替换为 <tbody> .看全图我准备了Stackblitz DEMO ,希望它会有所帮助......另外,这个例子可能很明显是人为的,但这就是我试图用最少的代码重现问题的原因。所以问题应该在给定的基础设施中有一个解决方案。

更新

@AlexG 找到了替换中间件的简单方法 divtbody stackblitz 演示一开始显示了不错的结果。但是当我尝试将它应用到本地项目时,我遇到了新问题:浏览器会自行安排 tbody在表的动态内容准备好呈现之前,这导致两个嵌套的 tbody在最终 View 中,这似乎与 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 demo没有这个问题,只有tbody my-comp存在。但是我本地开发环境中的项目完全相同。所以我仍在努力寻找一种方法如何删除中间my-comp容器。

更新 2

demo已根据@markdBC 建议的解决方案进行了更新。

最佳答案

我的回答受到 Slim 对此处发现的类似问题的回答的启发:https://stackoverflow.com/a/56887630/12962012 .

你可以去掉中间的<div my-comp>通过

  1. 创建 TemplateRef表示 MyComp 模板的对象MyComp 内的组件组件。
  2. 访问此 TemplateRef来自结构指令的对象。
  3. 使用 TemplateRef 在 View 容器内创建嵌入式 View 来自结构指令的对象。

生成的代码类似于:

MyComp组件

@Component({
selector: "[my-comp]",
template: `
<ng-template #mytemplate>
<tr>
<td>custom td</td>
</tr>
<ng-template
*ngFor="let item of data"
[ngTemplateOutlet]="template"
[ngTemplateOutletContext]="{ $implicit: item }"
></ng-template>
</ng-template>
`
})
export class MyComp {
public template: TemplateRef<any>;
public data: any;
@ViewChild("mytemplate", { static: true }) mytemplate: TemplateRef<any>;
}

MyDir指令

export class MyDir implements OnInit {
private version: string;
private data: any;

constructor(
private templateRef: TemplateRef<any>,
private viewContainer: ViewContainerRef,
private resolver: ComponentFactoryResolver
) {}

@Input() set myDirOf(data: any) {
this.data = data;
}

ngOnInit() {
const compFactory = this.resolver.resolveComponentFactory(MyComp);
const componentRef = compFactory.create(this.viewContainer.injector);
componentRef.instance.data = this.data;
componentRef.instance.template = this.templateRef;
this.viewContainer.createEmbeddedView(componentRef.instance.mytemplate);
}
}

生成的 HTML 类似于:

<table>
<tr><td>custom td</td></tr>
<tr><td>item 1</td></tr>
<tr><td>item 2</td></tr>
</table>

我已经在 https://stackblitz.com/edit/table-no-div-wrapper 准备了 StackBlitz 演示.

关于javascript - 在 Angular 结构指令中使用动态组件会产生额外的 HTML 标签。如何去除或更换它?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58826887/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com