How to point other components in the else part of *ngIf

Issue

With extension of my previous question, here are another scenario where I need to use a template in else part of *ngIf

Here is my current code where I am using loading spinner on each page until API response returns

   <ng-container *ngIf="!isLoading; else spinner">
         <form [formGroup]="myForm" novalidate (ngSubmit)="submit()" >
            // form content 
         </form>
    </ng-container>
    <ng-template #spinner>
        <div class="fa-3x tc">
            <i class="fas fa-spinner fa-spin"></i>
        </div>
    </ng-template>

this way we have to write the same #spinner component on every page so I have created a component with the same content.

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

@Component({
    selector: 'app-display-loading',
    styles: [`.load__spinner { color: black; text-align: center; font-size: 30px;}`],
    template: `
        <ng-template>
            <div class="load__spinner"> <i class="fas fa-spinner fa-spin"></i></div>
        </ng-template>
    `,
    preserveWhitespaces: true
})

export class DisplayLoadingComponent {
    constructor() {
        console.log('display loading called');
    }
}

Now my question is how to use this <app-display-loading> component within *ngIf

or this may be not the right way. Kindly suggest how to do this.

Solution

Angular structural directive can help us to point other component in the else part of ngIf directive.

All you need to do is to just create directive that will supplement built-in ngIf directive.

The final syntax should look like:

<div *ngIf="model withLoading">
  Model
</div>

which is just a sugar for:

<ng-template [ngIf]="model" [ngIfWithLoading]="null">
  <div>
      Model
  </div>
</ng-template>

And here is directive itself:

@Directive({
  selector: '[ngIfWithLoading]',
})
export class LoadingDirective {
  @Input() set ngIf(val: any) {
    if (!val) {
      const factory = this.resolver.resolveComponentFactory(LoadingComponent);
      this.vcRef.createComponent(factory)
    }
  };

  constructor(private vcRef: ViewContainerRef, private resolver: ComponentFactoryResolver) { }
}

So as soon as model is false the directive above will place your LoadingComponent instead of model template.

Don’t forget to include LoadingComponent into entryComponents array

Ng-run Example

See also

Answered By – yurzui

Answer Checked By – Robin (AngularFixing Admin)

Leave a Reply

Your email address will not be published.