Using ngTemplateOutlet to pass ng-template to a child component in Angular 5

I am looking to develop a versatile component that can utilize custom templates for data rendering, while consolidating the business logic to prevent redundancy.

Imagine this use case: a paginated list. The pagination logic should be housed within the component to avoid repetition, but the styling/presentation of the data should be customizable using ng-templates.

I have implemented the ngTemplateOutlet in the child component to reference the ng-template in the parent, however, I am encountering an error:

ERROR TypeError: templateRef.createEmbeddedView is not a function

The first ng-container in the reusable component is functioning properly, but the last three are causing the error message.

This is the code snippet for my reusable component:

@Component({
  selector: 'reusable-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 how the component is utilized:

<reusable-component>
    <ng-template let-result>
        // able to access 'result' variable here without issues.
    </ng-template>

    <ng-template #loading>
        // Facing the mentioned error
    </ng-template>

    <ng-template #loadingMore>
        // Facing the mentioned error
    </ng-template>

    <ng-template #noResults>
       // Facing the mentioned error
    </ng-template>
</reusable-component>

Any suggestions on resolving the issue with the last three ng-container lines in the reusable component so they can render the ng-templates appropriately?

Answer №1

After referencing this helpful article, I was able to solve the issue.

I made modifications by including additional @ContentChild elements in the reusable component and adjusted the ngTemplateOutlet references accordingly.

@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>

No changes were required in the logic of the parent component.

Answer №2

INCLUDE THE FOLLOWING CODE FOR COMPONENT RE-USABILITY

Within the '.HTML' file:

<ng-container [ngTemplateOutlet] = "yourTemplateName"
[ngTemplateOutletContext] = "{$ implicit: {name: 'Alice', lastName: 'Smith'}">
</ng-container>
  • The data from [NgTemplateOutletContext] will be sent to the parent component, where '$ implicit' can contain any desired information for the PARENT component.

In the '.ts' file OF THE REUSABLE COMPONENT, insert the following code WITHIN YOUR CLASS

@ContentChild ('yourTemplateName') yourTemplateName: TemplateRef <any>;

PARENT COMPONENT (USES THE RE-USED COMPONENT)

Add this code to the '.html' file

<ng-template #yourTemplateName let-myData>
<p> {{myData.name}} {{myData.lastName}} </p>
</ng-template>

ANGULAR VERSION: 9/10 DOCUMENTATION: https://angular.io/api/common/NgTemplateOutlet

  • The documentation may not demonstrate ngTemplateOutlet usage across different components, but it provides a useful starting point.

Answer №3

In my opinion, utilizing the @ContentChildren is the most effective approach. You can set [ngTemplateOutlet] as a component variable, allowing you to specify the desired ng-template using filter or find from the @ContentChildren QueryList.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Passing data from ModalService to a component

Currently, I am attempting to utilize the ngx-bootstrap-modal in order to transfer data from a modal service to a modal component. While reviewing the examples, it is suggested to use the following code: this.modalService.show(ModalContentComponent, {init ...

I am unable to access the 'UserName' property in Angular 2 because it is undefined

I have tried multiple solutions, but none of them have helped me solve this issue... I am struggling to identify the problem in my code... HTML CODE :: <input type="text" class="form-control" placeholder="Please Enter Your Username" [(ngModel)]="curr ...

Exploring the inner workings of the canDeactivate guard feature in Angular

Exploring the concept of guards in Angular has sparked a question in my mind. Why can't we simply have a class with a deactivate method that we can import and use as needed? The provided code snippets illustrate my confusion. export interface CanComp ...

What are the advantages of combining the website URL and API URL within the Angular service?

When deploying my application in a production environment, I encounter an issue with the URL addresses. The web address is , while the API address is . However, when making a request to the API through Angular, the URLs get concatenated into . This issue d ...

Angular: monitoring changes in HTML content within a Component or Directive

I have a situation where I am retrieving HTML content from a REST endpoint using a directive and inserting it into a div element using [innerHTML]. Once this HTML content is rendered, I would like to manipulate it by calling a global function. My approach ...

I'm encountering an issue where the Angular application won't start on the DigitalOcean server running Ubuntu. Any

I have uploaded the distributed file of my Angular app to a server, but I am having trouble running the app on the server. Whenever I try to use ng-serve in Putty on my dist folder, I just get a blank output and nothing happens (refer to the image linked ...

Only implement valueChanges on the second step of the form

I am utilizing the mat-stepper with a single form. My stepper has two steps only. I am looking to make an API request for every input value change, but only when the user is on the second step. How can I accomplish this? .ts ngOnInit() { this.formGr ...

Getting the perfect typings installed from DefinitelyTyped

In my current attempt to install typings (version 1.3.2) for the malihu-custom-scrollbar-plugin, I am facing an issue with some wrong type identification error (Error TS1110: Type expected). This error is caused by the use of string literal types syntax li ...

Implementing data binding in ngStyle with Angular

Having trouble binding data with Angular 8, I attempted the following method: <div class="speed" style="background-image: url('http://example.com/assets/images/meter.png')" [ngStyle]="{'--p':result.percentage}"></div> The ...

Steps to dynamically include a marker on a Google Maps component using HTTPGET in Angular 6

I am currently working on an Angular 6 application that involves integrating the Google Javascript API with AGM. So far, the map functions well except for dynamically adding markers using an http get request. Here is a snippet of the component.html: < ...

Angular mistakenly redirects to the local host at port 4200 with a hash symbol

After using this.router.navigate(['newcard']);, the URL loads correctly but then quickly redirects to localhost:4200/#. This is how I am redirecting from the showcard component to the newcard component: <a href="#" class="btn b ...

What could be causing the TypeScript exhaustive switch check to malfunction?

How come the default case in the switch statement below does not result in an exhaustive check where 'item' is correctly identified as of type 'never'? enum Type { First, Second } interface ObjectWithType { type: Type; } c ...

What is the best way to "connect" an interface in TypeScript?

I'm working on creating a child interface that mirrors the structure of a base interface. Any tips on how to achieve this? interface BaseInterface { api: { [key: string]: string }; ui: { [key: string]: string }; } interface ChildInterface { / ...

Guide on injecting a service into a directive within Angular version 13

I have a directive named UniqueCodeDirective that I am using to validate a reactive form. The reason for this is because I require additional information beyond the form control value, which can be obtained from the routing parameters. However, I am encoun ...

Issues with Await and Async functionality in Angular and Ionic 4 causing unexpected behavior

Struggling to show error messages during the sign-up process? Constantly encountering the same issue in your code? The error TS1308 is throwing you off: 'await' expression is only allowed within an async function. Take a look at this problemati ...

Enhancing the TypeScript typings of modules in Angular 2

In my Angular2 application, I am facing an issue with an external NPM package that has an outdated typings file. This means there are functions within the package that are present but not declared in the typings file. My main goals are: To create and ut ...

Can you retrieve the form control names in an array within an Angular reactive form?

<div *ngFor="let response of responsesForm?.get('responses')?.value; let i = index;"> <div [innerHTML]="response.content"></div> <textarea formControlName="response.content"></texta ...

Learn how to dynamically include files within the script tag using Angular4

Is there a way to dynamically include a remote file in a script tag using Angular4? For instance, if I have a file named https://rawgithub.com/eligrey/FileSaver.js/master/FileSaver.js as a query string parameter in the URL located in the address bar http: ...

Exploring SubjectBehavior within my UserService and Profile Component

Within my ShareService, I have the following code snippet: isLogin$:BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false); <==== default value is false CheckUser = this.isLogin$.asObservable(); public isLogin (bool){ ...

Ways to resolve: The JSX component does not contain any construction or call signatures

I've been grappling with a persistent issue regarding the creation of custom elements dynamically in React TypeScript. If you're curious, you can check out the question here. const generalButtons: MenuButton[] = [ { text: "New Cl ...