Reputation: 323
Im trying to select templates dynamically in a view simply by referencing them with the traditional "#" character of Angular 2. In my project i handle errors and display them to a user, I have a dialog component which should have its content html based dynamically injected, so thats why im using templates.
I read some articles which shows a way of how to do it when i already know the name of the template reference in my case i dont know the name of the reference i get the name on runtime. I followed this guide in particular: https://www.bennadel.com/blog/3101-experimenting-with-dynamic-template-rendering-in-angular-2-rc-1.htm
So currently my dialog component has the following view:
<template #err_1 let-property1="p1" let-property2="p2">
property1: {{p1}}
property2: {{p2}}
</template>
<template #err_2 let-property1="p1" let-property2="p2">
<p *ngIf="p1">{{p1}}</p>
property2: {{p2}}
</template>
<!--The code for the template directive i took from the guide in the link above-->
<tem [render]="templateRef"
[context]="context">
</tem>
In my dialog.ts I have the following code:
@Component({
selector: 'error-dialog',
queries: {
templateRef: new ViewChild("err_1")
},
templateUrl: './dialog.html'
})
...
"TemplateRendererDirective" directive source i took from their guide from the link above. pay attention that what confused me: templateRef basically gets an object of: "ViewChild" even though the directive eventually gets TemplateRef instance, how this is possible?
so only if i know which error template i want to render for example: "err_1" i just referencing it beforehand in dialog.ts, but its not the case, i want dynamically tell i want to render "err_1", "err_2" etc.. and give the context (which is the object to fill that template with data - p1, p2 for the example, also dynamically)
Is it possible to do it?
Upvotes: 3
Views: 4413
Reputation: 214007
As i mentioned in comments you can try to use @ViewChildren
to do it working. But i use additional directive TemplateNameDirective
to manipulate template's name
.
Here's how it looks:
@Directive({
'selector': 'template[name]'
})
export class TemplateNameDirective {
@Input() name: string;
constructor(public templateRef: TemplateRef<any>) {}
}
@Component({
selector: 'error-dialog',
template: `
<template name="err_1" let-item>
property1: {{item.p1}}
property2: {{item.p2}}
</template>
<template name="err_2" let-item>
<p *ngIf="item.p1">{{item.p1}}</p>
property2: {{item.p2}}
</template>
<!--
I use ngTemplateOutlet directive
https://angular.io/docs/ts/latest/api/common/index/NgTemplateOutlet-directive.html
-->
<template [ngTemplateOutlet]="templateRef" [ngOutletContext]="{ $implicit: context }">
</template>
`
})
export class ErrorDialogComponent {
@ViewChildren(TemplateNameDirective) children: QueryList<TemplateNameDirective>;
templateRef: TemplateRef<any>;
context: any;
public setContent(errTemplateName, context) {
this.templateRef = this.children.toArray()
.find(x => x.name === errTemplateName).templateRef;
this.context = context;
}
}
Parent view:
<error-dialog #dialogRef></error-dialog>
<button (click)="dialogRef.setContent('err_1', { p1: 'test'})">Test err_1</button>
<button (click)="dialogRef.setContent('err_2', { p2: 'test2'})">Test err_2</button>
Notice: i am passing ngOutletContext
like object with $implicit
property.
using the key $implicit in the context object will set it's value as default.
It works as follows:
[ngOutletContext]="{ $implicit: row }" ==> <template let-row>
[ngOutletContext]="{ item: row }" ==> <template let-row="item">
Upvotes: 5