Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular 5: Pass ng-template down to child component using ngTemplateOutlet

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?

like image 266
Lansana Camara Avatar asked Feb 18 '18 14:02

Lansana Camara


2 Answers

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.

like image 127
Lansana Camara Avatar answered Sep 28 '22 08:09

Lansana Camara


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>
  • [NgTemplateOutletContext] data will be sent to the parent component. Remembering that '$ implicit' can receive any data you want to send to the FATHER component

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

  • The documentation does not show the use of ngTemplateOutlet in different components, but it already helps in something.
like image 23
Arthur Cabral Avatar answered Sep 28 '22 10:09

Arthur Cabral