I'm trying to create a component that accepts multiple templates as inputs. This is the example I have:
@Component({
selector: 'data-list',
styles: [
require('./data-list.component.scss')
],
template: `
<ng-template
*ngFor="let item of itemsData"
ngFor let-item [ngForOf]="[item]" [ngForTemplate]="itemTemplate"
></ng-template>
`
})
export class DataListComponent {
@Input() itemsData: any[];
@ContentChild(TemplateRef) itemTemplate: TemplateRef<ElementRef>;
}
As you can see it's a fairly simple component that I'm trying out. This component simply accepts the data of the items to be displayed as well as the template of the item. This component can be used like so:
<data-list [itemsData]="data">
<ng-template let-item>
<h1>{{ item.header }}</h1>
<div>{{ item.content }}</div>
</ng-template>
</data-list>
As shown above I'm passing the template using ng-content
which is then read by the DataListComponent
with @ContentChild(TemplateRef) itemTemplate: TemplateRef<ElementRef>;
.
My question is whether it is possible to pass multiple templates to a component.
As an example one would pass the template for the items, but a different template is needed in case it's the first item. This would mean that the check of the first item would be made in the DataListComponent
but then use a template specified by the component using it.
Simple example:
I can do something like so to cater for this:
@Component({
selector: 'data-list',
styles: [
require('./data-list.component.scss')
],
template: `
<span *ngFor="let item of itemsData; let i = index" >
<ng-template *ngIf="i > 0; else nextTmpl"
ngFor let-item [ngForOf]="[item]" [ngForTemplate]="itemTemplate"
></ng-template>
</span>
<ng-template #nextTmpl>
Next
</ng-template>
`
})
However like so the "Next Template" is not specified by the component using the DataListComponent
and therefore will always be the same template.
You can simply extend your base component and overwrite the template. This allows you to have different components with the exact same functionality, but different templates. Save this answer.
Note Although it's possible for a component to render multiple templates, we recommend using an if:true|false directive to render nested templates conditionally instead. Create multiple HTML files in the component bundle.
In order to have a template rendered in that container, we use the *ngTemplateOutlet to pass a reference to an existing template, such as the one we created earlier. We use @Input to pass a TemplateRef to our component.
TemplateReflinkRepresents an embedded template that can be used to instantiate embedded views. To instantiate embedded views based on a template, use the ViewContainerRef method createEmbeddedView() .
I solved this same issue by using the string selector available to the ContentChild decorator.
You will need to specify template variables when using your data-list component:
<data-list [itemsData]="data">
<ng-template #firstItemTemplate let-item>
<h1 style="color:red;">{{ item.header }}</h1>
<div>{{ item.content }}</div>
</ng-template>
<ng-template #standardTemplate let-item>
<h1>{{ item.header }}</h1>
<div>{{ item.content }}</div>
</ng-template>
</data-list>
Then, inside your data-list component class, assign the template variables to local variables on the component:
@Input() itemsData: any[];
@ContentChild('firstItemTemplate') firstItemTemplate: TemplateRef<ElementRef>;
@ContentChild('standardTemplate') standardTemplate: TemplateRef<ElementRef>;
After this, you'll be able to render the passed-in templates from your data-list component.
@Component({
selector: 'data-list',
styles: [
require('./data-list.component.scss')
],
template: `
<span *ngFor="let item of itemsData; let i = index" >
<ng-template *ngIf="i == 0; else nextTmpl"
ngFor let-item [ngForOf]="[item]" [ngForTemplate]="firstItemTemplate"
></ng-template>
<ng-template #nextTmpl
ngFor let-item [ngForOf]="[item]" [ngForTemplate]="standardTemplate"
></ng-template>
</span>
`
})
Try this instead.
@Component({
selector: 'data-list',
styles: [
require('./data-list.component.scss')
],
template: `
<ng-template ngFor [ngForOf]="itemsData" [ngForTemplate]="itemTemplate"></ng-template>
`
})
export class DataListComponent {
@Input() itemsData: any[];
@ContentChild(TemplateRef) itemTemplate: TemplateRef<ElementRef>;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With