I want to create a re-useable component that can take custom templates to render data, while composing the business logic so I don't have to repeat myself.
Example use case: a paginated list. The pagination logic should be in the re-useable component so it's only written once, but the themeing/presentation of the data should be customizeable using ng-template
's.
I am using ngTemplateOutlet
in the child component to reference the ng-template
in the parent, but I am getting this error:
ERROR TypeError: templateRef.createEmbeddedView is not a function
The first ng-container
in the re-useable component works fine, it's the last 3 that are giving the error.
This is my re-useable component:
@Component({
selector: 'reuseable-component',
...
})
export class ChildComponent {
@ContentChild(TemplateRef) templateRef;
}
<ng-container *ngIf="...">
<ng-template [ngTemplateOutlet]="templateRef"
[ngTemplateOutletContext]="{$implicit: result}">
</ng-template>
</ng-container>
<ng-container *ngIf="..." [ngTemplateOutlet]="loading"></ng-container>
<ng-container *ngIf="..." [ngTemplateOutlet]="loadingMore"></ng-container>
<ng-container *ngIf="..." [ngTemplateOutlet]="noResults"></ng-container>
This is the usage:
<reuseable-component>
<ng-template let-result>
// I have access to 'result' variable here, works fine.
</ng-template>
<ng-template #loading>
// This gives the error above
</ng-template>
<ng-template #loadingMore>
// This gives the error above
</ng-template>
<ng-template #noResults>
// This gives the error above
</ng-template>
</reuseable-component>
How can I fix the last 3 ng-container
lines in the re-useable component so they render the ng-template
's in my usage?
Solved this with a little help from this article.
Added more @ContentChild
's in the re-useable component, and changed the ngTemplateOutlet
's to reference the content childs.
@Component({
selector: 'reuseable-component',
...
})
export class ChildComponent {
@ContentChild(TemplateRef) templateRef;
@ContentChild('loading') loadingRef: TemplateRef<any>;
@ContentChild('loadingMore') loadingMoreRef: TemplateRef<any>;
@ContentChild('noResults') noResultsRef: TemplateRef<any>;
}
<ng-container *ngIf="...">
<ng-template [ngTemplateOutlet]="templateRef"
[ngTemplateOutletContext]="{$implicit: result}">
</ng-template>
</ng-container>
<ng-container *ngIf="...">
<ng-template [ngTemplateOutlet]="loadingRef"></ng-template>
</ng-container>
<ng-container *ngIf="...">
<ng-template [ngTemplateOutlet]="loadingMoreRef"></ng-template>
</ng-container>
<ng-container *ngIf="...">
<ng-template [ngTemplateOutlet]="noResultsRef"></ng-template>
</ng-container>
The logic in the parent component didn't need to change.
ADD THE FOLLOWING IN THE COMPONENT TO BE RE-USED
In the '.HTML' file:
<ng-container [ngTemplateOutlet] = "yourNameReference"
[ngTemplateOutletContext] = "{$ implicit: {name: 'Arthur', lastName: 'Lemos'}">
</ng-container>
In the '.ts' file OF THE REUSABLE COMPONENT add the following code WITHIN YOUR CLASS
@ContentChild ('yourNameReference') yourNameReference: TemplateRef <any>;
FATHER COMPONENT (RECEIVES THE RE-USED COMPONENT)
Add the following code to the '.html' file
<ng-template #yourNameReference let-myDataa>
<p> {{myDataa.name}} {{myDataa.lastName}} </p>
</ng-template>
ANGULAR VERSION: 9/10 DOCUMENTATION: https://angular.io/api/common/NgTemplateOutlet
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