Reputation: 113
I’m trying to create a (structural) directive that inserts a TemplateRef
, but where the TemplateRef
is defined "somewhere else".
I sometimes want to insert arbitrary content into an existing element, but for DOM reasons, it’s important that it not be a component (though an attribute-like component is fine).
Example:
<table>
<tr my-row-component></tr>
</table>
@Component({
selector: 'tr[my-row-component]'
template: `<td>...</td><td>...</td><td>...</td>...`
})
Now from here, I’d want to do the same thing, but insert 2 rows into my table. So I was hoping to do something like:
<table>
<ng-template myTwoRowsDirective></ng-template>
</table>
The issue is that:
How could I get a TemplateRef
inside a Structural directive, but that is not passed in by the caller of the directive?
@Directive({selector: '[myTwoRowsDirective]'})
export class MyTwoRowsDirective {
constructor(
viewContainerRef: ViewContainerRef) {
const templateRef = ???; // Reference to template defined elswhere
viewContainerRef.createEmbeddedView(templateRef, this.context);
}
}
Upvotes: 2
Views: 2619
Reputation: 3109
Don't know if this is a recommended practice, but this seems to work (haven't tested it on your use case though):
@Component({
template: `
<ng-template #helloRef>
<h1>hello</h1>
</ng-template>
`
})
export class TemplatesComponent {
@ViewChild('helloRef', { static: true }) public helloRef: TemplateRef<any>;
}
@Directive({
selector: 'whatever-component'
})
export class CustomizeWhateverDirective implements AfterViewInit {
private static componentRef: ComponentRef<TemplatesComponent>;
constructor(
@Self() private whatever: WhateverComponent,
private resolver: ComponentFactoryResolver,
private _vcr: ViewContainerRef
) {}
ngAfterViewInit(): void {
const componentRef = this.getComponentRef();
const helloRef = componentRef.instance.helloRef;
this.whatever.helloTemplate = helloRef;
}
private getComponentRef() {
if (!CustomizeWhateverDirective.componentRef) {
const factory = this.resolver.resolveComponentFactory(TemplatesComponent);
CustomizeWhateverDirective.componentRef = this._vcr.createComponent(factory);
}
return CustomizeWhateverDirective.componentRef;
}
}
This code sets the helloTemplate attribute of all Whatever components in my project.
So the trick is to have a component with the templateRef (TemplatesComponent in the example), and create that component (through viewContainerRef.createComponent) and access the templateRef.
Upvotes: 4