angularangular2-changedetectionng-template

ngTemplateOutlet directive handler fires multiple times


There is a simple Angular web app that uses ng-template. It uses ngTemplateOutlet directive. A handler method (loadtemplate) is set for this directive, but this method is called multiple times when a user clicks Add button. Component html code

It's not clear for me why it happens. I mean why it occurs multiple times if users collection is empty. Could somebody please explain it?

Component typescript code

Here is the link to the app https://stackblitz.com/edit/stackblitz-starters-q2tper?file=src%2Fapp%2Fapp%2Fapp.component.html

I tried to find similar questions on stackoverflow,but didn't get any results.


Solution

  • The loadTemplate will get fired multiple times when a button is clicked due to change detection; here it would be from the row addition.

    Another one is the fact that change detection runs twice on the DEV server.

    Third one, I'm not sure, might be due to template rendering.

    Anyway, the point I want to make is that change detection calling the function multiple times is not a problem unless you have a heavy operation happening inside the function, for example: An array operation like find runs over 100+ records for each change detection cycle, which is not the case for you, so it's OK.

    I modified the function to simple ternary condition and it works great.

    Working example below:

    import { Component, OnInit, TemplateRef, ViewChild } from '@angular/core';
    import { User } from '../user';
    import { FormsModule } from '@angular/forms';
    import { CommonModule } from '@angular/common';
    
    @Component({
      selector: 'app-app',
      standalone: true,
      imports: [FormsModule, CommonModule],
      templateUrl: './app.component.html',
      styleUrl: './app.component.css',
    })
    export class AppComponent {
      @ViewChild('readOnlyTemplate', { static: false })
      readOnlyTemplate: TemplateRef<any> | null;
      @ViewChild('editTemplate', { static: false })
      editTemplate: TemplateRef<any> | null;
      editedUser: User | null = null;
      users: Array<User>;
      isNewRecord: boolean = false;
      statusMessage: string = '';
      userId = 0;
    
      constructor() {
        this.users = new Array<User>();
      }
    
      addUser() {
        console.log('addUser');
        this.userId++;
        this.editedUser = new User(`${this.userId}`, '', 0);
        this.users.push(this.editedUser);
        this.isNewRecord = true;
      }
    
      editUser(user: User) {
        this.editedUser = new User(user._id, user.name, user.age);
      }
    
      loadTemplate(user: User, index: number) {
        console.log('load template');
        if (this.editedUser && this.editedUser._id === user._id) {
          return this.editTemplate;
        } else {
          return this.readOnlyTemplate;
        }
      }
    }
    

    HTML

    <h1>List of users</h1>
    <button (click)="addUser()">Add</button>
    <table>
      <tr>
        <th>Id</th>
        <th>Name</th>
        <th>Age</th>
        <th></th>
      </tr>
      @for(user of users; track user._id){
      <tr>
        <ng-template
          [ngTemplateOutlet]="
            editedUser?._id === user?._id ? editTemplate : readOnlyTemplate
          "
          [ngTemplateOutletContext]="{ $implicit: user }"
        >
        </ng-template>
      </tr>
      }
    </table>
    <div>{{ statusMessage }}</div>
    {{editedUser | json}}
    <ng-template #readOnlyTemplate let-user>
      <td>{{ user._id }}</td>
      <td>{{ user.name }}</td>
      <td>{{ user.age }}</td>
      <td>
        <button (click)="editUser(user)">Change</button>
      </td>
    </ng-template>
    
    <ng-template #editTemplate>
      <td>
        <input [(ngModel)]="editedUser!._id" readonly disabled />
      </td>
      <td>
        <input [(ngModel)]="editedUser!.name" />
      </td>
      <td>
        <input type="number" [(ngModel)]="editedUser!.age" />
      </td>
      <td></td>
    </ng-template>
    

    Stackblitz Demo