Search code examples
htmlangularangular2-directivesangular17

Angular 17 - How to indicate both else to same ng-template for *ngIf using @if @else


I am trying to convert my code directives from Angular 16 to Angular 17. However, I am unable to achieve the reference in Angular 17 so that for both else it will refer to the same ng-template.

<div *ngIf="movies; else noTracks">
    <div *ngIf="movies.length>0; else noTracks">
        <h6 class="m-b-20 m-t-40 p-b-5 b-b-default f-w-600">Favorites</h6>
        <div class="row">
            <div class="col-sm-6">
                <p class="m-b-10 f-w-600">Recent</p>
                <h6 class="text-muted f-w-400">{{movies[movies.length-1].title}}
                    -
                    {{movies[movies.length-1].rating}}</h6>
            </div>
            <div class="col-sm-6">
                <p class="m-b-10 f-w-600">Total</p>
                <h6 class="text-muted f-w-400">{{ movies.length}}</h6>
            </div>
        </div>
    </div>
</div>

<ng-template #noTracks>
    <h6 class="m-b-20 m-t-40 p-b-5 b-b-default f-w-600">Favorites</h6>
    <div class="row">
        <div class="col-sm-6">
            <p class="m-b-10 f-w-600">Recent</p>
            <h6 class="text-muted f-w-400">NA</h6>
        </div>
        <div class="col-sm-6">
            <p class="m-b-10 f-w-600">Total</p>
            <h6 class="text-muted f-w-400">0</h6>
        </div>
    </div>
</ng-template>

In Angular 17 I am trying to achieve the above using @if and @else without using || cause for type never error I will get. Further, I want how we can achieve this.

Note: Don't combine @if statements.

@if (movies) {
  @if (movies.length>0) {
    <h6 class="m-b-20 m-t-40 p-b-5 b-b-default f-w-600">Favorites</h6>
    <div class="row">
      <div class="col-sm-6">
        <p class="m-b-10 f-w-600">Recent</p>
        <h6 class="text-muted f-w-400">{{movies[movies.length-1].title}}
            -
            {{movies[movies.length-1].rating}}</h6>
      </div>
      <div class="col-sm-6">
        <p class="m-b-10 f-w-600">Total</p>
        <h6 class="text-muted f-w-400">{{ movies.length}}</h6>
      </div>
    </div>
  } @else {
    <h6 class="m-b-20 m-t-40 p-b-5 b-b-default f-w-600">Favorites</h6>
    <div class="row">
      <div class="col-sm-6">
        <p class="m-b-10 f-w-600">Recent</p>
        <h6 class="text-muted f-w-400">NA</h6>
      </div>
      <div class="col-sm-6">
        <p class="m-b-10 f-w-600">Total</p>
        <h6 class="text-muted f-w-400">0</h6>
      </div>
    </div>
  }
}

Solution

  • Basically the *ngIfElse syntax is the same as the @if @else statement.

    The noTracks <ng-template> remains, and to render the template you need the <ng-container> element with [ngTemplateOutlet].

    @if (movies) { 
      @if (movies.length > 0) {
        ...
      } @else { 
        <ng-container [ngTemplateOutlet]="noTracks"></ng-container>
      } 
    } @else { 
      <ng-container [ngTemplateOutlet]="noTracks"></ng-container>
    } 
    

    Make sure that you have imported CommonModule or NgTemplateOulet in your component.

    Demo @ StackBlitz

    Note that I will prefer combining both @if statements into a single @if which simplifies the (else) template. Since the Post Owner requests to maintain the existing structure as *ngIfElse syntax, I wrote this answer.