问题
I have quite complex infrastructure in my project which contains of
- host component
- structural directive used in host component's template (MyDir)
- another component used in structural directive (MyComp)
host component
@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' } ];
}
structural directive
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;
}
}
structural directive's component
@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;
}
The output is
custom td
item 1
item 2
which is fine except the markup which is
<table>
<div my-comp>
<tr><td>custom td</td></tr>
<tr><td>item 1</td></tr>
<tr><td>item 2</td></tr>
</div>
</table>
Problem
I want to remove intermediate <div my-comp>
from the result view or at least replace it with <tbody>
. To see the whole picture I prepared Stackblitz DEMO, hope it will help... Also, it might be obvious the example is artificial, but this is what I came with trying to reproduce the issue with minimal code. So the problem should have a solution in the given infrastructure.
Update
@AlexG found simple way to replace intermediate div
with tbody
and stackblitz demo showed a good result at first. But when I tried to apply it to my project locally I faced new issue: browser arranges its own tbody
before the dynamic contents of the table are ready to render, which results in two nested tbody
in the end view, which seems inconsistent per html specs
<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 has no such problem, only tbody my-comp
is present. But exactly the same project in my local dev environment does. So I'm still trying to find a way how to remove intermediate my-comp
container.
回答1:
Change the selector of your component from [my-comp]
to tbody [my-comp]
and your will have a <tbody my-comp>
instead of a <div my-comp>
which would be sufficient if I understood you correctly.
来源:https://stackoverflow.com/questions/58826887/using-dynamic-component-within-angular-structural-directive-produces-extra-html