Search code examples
angularangular-templateangular-template-variable

How to create template reference inside the `ngFor` loop with angular?


i am trying to create template reference through ngFor loop. but not works.

ts file:

import { Component, VERSION } from '@angular/core';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent  {
  members = [
    {
      name: 'name1',
      id:"one"
    },
    {
      name: 'name2',
      id:"two"
    },
    {
      name: 'name3',
      id:"three"
    } 
  ]
}

template:

<div class="container">
  <h2>Test popover</h2>
  <p>
    How to declare a dynamic template reference variable inside a ngFor element?
  </p>
</div>

<div *ngFor="let member of members">
  <ng-container [ngTemplateOutlet]="{{member.id}}"
    >Hello, <b>{{ member.name }}</b
    >!</ng-container
  >
</div>

<ng-template #one> one </ng-template>
<ng-template #two> two </ng-template>
<ng-template #three> three </ng-template>

Live demo

I am getting an error as:

Type '{ "": any; }' is not assignable to type 'TemplateRef<any>'. Object literal may only specify known properties, and '""' does not exist in type 'TemplateRef<any>'.


Solution

  • Update:

    If you want to pass ngTemplate to child, you can use contentChild

    import { Component, Input, ContentChild, TemplateRef } from '@angular/core';
    
    @Component({
      selector: 'hello',
      template: `
      <div *ngFor="let member of members">
          {{member.name}} <ng-container [ngTemplateOutlet]="this[member.id]"></ng-container>
      </div>
      `,
      styles: [`h1 { font-family: Lato; }`],
    })
    export class HelloComponent {
      @ContentChild('one') one: TemplateRef<any>;
      @ContentChild('two') two: TemplateRef<any>;
      @ContentChild('three') three: TemplateRef<any>;
      @Input() members: any;
    }
    

    forked stackblitz

    Solution1:

    Instead of hardcoding the template names, you can just render based on the index

    <div class="container">
      <h2>Test popover</h2>
      <p>
        How to declare a dynamic template reference variable inside a ngFor element?
      </p>
    </div>
    <div *ngFor="let member of members; let i = index">
      <ng-container *ngIf="temps">
        <ng-container [ngTemplateOutlet]="temps.toArray()[i]"
          >Hello, <b>{{ member.name }}</b
          >!</ng-container
        ></ng-container
      >
    </div>
    
    <ng-template #temp> one </ng-template>
    <ng-template #temp> two </ng-template>
    <ng-template #temp> three </ng-template>
    

    forked stackblitz

    Solution2:

    You can chain ternary conditions so that you get the output as required

    <div class="container">
      <h2>Test popover</h2>
      <p>
        How to declare a dynamic template reference variable inside a ngFor element?
      </p>
    </div>
    
    <div *ngFor="let member of members">
      <ng-container
        *ngTemplateOutlet="
          member.id === 'one' ? one : member.id === 'two' ? two : three
        "
        >Hello, <b>{{ member.name }}</b
        >!</ng-container
      >
    </div>
    
    <ng-template #one> one </ng-template>
    <ng-template #two> two </ng-template>
    <ng-template #three> three </ng-template>
    

    forked stackblitz