[英]Using dynamic component within Angular structural directive produces extra HTML tag. How to remove or replace it?
我的項目中有相當復雜的基礎設施,其中包含
簡化版如下所示。
主機組件
@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;
}
output 是
自定義 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 找到了用tbody
替換中間div
的簡單方法,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 建議的解決方案進行了更新。
我的回答受到 Slim 對此處發現的類似問題的回答的啟發: https://stackoverflow.com/a/56887630/12962012 。
您可以通過以下方式刪除中間<div my-comp>
TemplateRef
object 代表MyComp
組件內的MyComp
組件的模板。TemplateRef
object。TemplateRef
object 在視圖容器內創建嵌入式視圖。生成的代碼如下所示:
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 演示。
將組件的選擇器從[my-comp]
更改為tbody [my-comp]
,您將擁有一個<tbody my-comp>
而不是<div my-comp>
如果我理解正確就足夠了。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.