196

How would I have multiple cases in an *ngIf statement? I'm used to Vue or Angular 1 with having an if, else if, and else, but it seems like Angular 4 only has a true (if) and false (else) condition.

According to the documentation, I can only do:

<ng-container *ngIf="foo === 1; then first else second"></ng-container>
<ng-template #first>First</ng-template>
<ng-template #second>Second</ng-template>
<ng-template #third>Third</ng-template>

But I want to have multiple conditions (something like):

<ng-container *ngIf="foo === 1; then first; foo === 2; then second else third"></ng-container>
<ng-template #first>First</ng-template>
<ng-template #second>Second</ng-template>
<ng-template #third>Third</ng-template>

But I'm ending up having to use ngSwitch, which feels like a hack:

<ng-container [ngSwitch]="true">
  <div *ngSwitchCase="foo === 1">First</div>
  <div *ngSwitchCase="bar === 2">Second</div>
  <div *ngSwitchDefault>Third</div>
</ng-container>

Alternately, it seems like a lot of the syntaxes I've got used to from Angular 1 and Vue aren't supported in Angular 4, so what would be the recommended way to structure my code with conditions like this?

Vadim Ovchinnikov
  • 13,327
  • 5
  • 62
  • 90
  • 1
    I was thinking that you hack was the best solution as it was most readable. However I've realised that angular switch statements allow for multiple criteria to match so you don't get that true elseif logic. – Tom Benyon May 14 '19 at 07:13

13 Answers13

270

Another alternative is to nest conditions

<ng-container *ngIf="foo === 1;else second"></ng-container>
<ng-template #second>
    <ng-container *ngIf="foo === 2;else third"></ng-container>
</ng-template>
<ng-template #third></ng-template>
CornelC
  • 4,974
  • 1
  • 21
  • 28
48

You can just use:

<ng-template [ngIf]="index == 1">First</ng-template>
<ng-template [ngIf]="index == 2">Second</ng-template>
<ng-template [ngIf]="index == 3">Third</ng-template>

unless the ng-container part is important to your design I suppose.

Here's a Plunker

Dylan
  • 4,703
  • 1
  • 20
  • 23
  • 8
    My example is a little simplistic, but expecting the 'else if' behavior such that `if (index === 1) else if (foo === 2)` which would have to be written `if (index === 1) if (index !== 1 && foo === 2)` which is a bit messy and more prone to errors, the more times we have to write inverse logic. –  May 05 '17 at 21:13
  • Have you looked at the plunker? I don't think I see the issue, index is only going to be 1 thing at a time. – Dylan May 05 '17 at 21:37
  • I think it's my example that's lacking explanation, here's an example in JS: `if (item === 'food' && kind === 'hamburger') {} else if (item === 'food' && kind === 'hotdog') {} else if (item === 'drink' && kind === 'beer') {} else if (item === 'drink' && kind === 'wine') {} else { /* could be poisonous */ }` –  May 05 '17 at 22:30
  • 1
    Still too much mutual exclusion in that example, but still, point is, I need to do if, else if, and else, not just if and else without writing tons of redundant logic. It seems like Angular 4's templates lack this kind of logic. –  May 05 '17 at 22:38
  • 1
    there are a few other options , this sounds like you may benefit from a `NgTemplateOutlet` with context like *ngTemplateOutlet="drink; context: beer", or maybe another component for categorizing. – Dylan May 05 '17 at 22:41
  • This does not emulate if, elseif, else functionality at all, for the reasons @ChrisSimpson said. – goat Dec 30 '17 at 22:41
  • Looks like the biggest benefits to switch would be the default condition and the fact that it's a little more obvious when reading the html that there is a choice – Simon_Weaver Jan 18 '18 at 01:51
41

This seems to be the cleanest way to do

if (foo === 1) {

} else if (bar === 99) {

} else if (foo === 2) {

} else {

}

in the template:

<ng-container *ngIf="foo === 1; else elseif1">foo === 1</ng-container>
<ng-template #elseif1>
    <ng-container *ngIf="bar === 99; else elseif2">bar === 99</ng-container>
</ng-template>
<ng-template #elseif2>
    <ng-container *ngIf="foo === 2; else else1">foo === 2</ng-container>
</ng-template>
<ng-template #else1>else</ng-template>

Notice that it works like a proper else if statement should when the conditions involve different variables (only 1 case is true at a time). Some of the other answers don't work right in such a case.

aside: gosh angular, that's some really ugly else if template code...

goat
  • 31,486
  • 7
  • 73
  • 96
27

You can use multiple way based on sitaution:

  1. If you Variable is limited to specific Number or String, best way is using ngSwitch or ngIf:

    <!-- foo = 3 -->
    <div [ngSwitch]="foo">
        <div *ngSwitchCase="1">First Number</div>
        <div *ngSwitchCase="2">Second Number</div>
        <div *ngSwitchCase="3">Third Number</div>
        <div *ngSwitchDefault>Other Number</div>
    </div>
    
    <!-- foo = 3 -->
    <ng-template [ngIf]="foo === 1">First Number</ng-template>
    <ng-template [ngIf]="foo === 2">Second Number</ng-template>
    <ng-template [ngIf]="foo === 3">Third Number</ng-template>
    
    
    <!-- foo = 'David' -->
    <div [ngSwitch]="foo">
        <div *ngSwitchCase="'Daniel'">Daniel String</div>
        <div *ngSwitchCase="'David'">David String</div>
        <div *ngSwitchCase="'Alex'">Alex String</div>
        <div *ngSwitchDefault>Other String</div>
    </div>
    
    <!-- foo = 'David' -->
    <ng-template [ngIf]="foo === 'Alex'">Alex String</ng-template>
    <ng-template [ngIf]="foo === 'David'">David String</ng-template>
    <ng-template [ngIf]="foo === 'Daniel'">Daniel String</ng-template>
    
  2. Above not suitable for if elseif else codes and dynamic codes, you can use below code:

    <!-- foo = 5 -->
    <ng-container *ngIf="foo >= 1 && foo <= 3; then t13"></ng-container>
    <ng-container *ngIf="foo >= 4 && foo <= 6; then t46"></ng-container>
    <ng-container *ngIf="foo >= 7; then t7"></ng-container>
    
    <!-- If Statement -->
    <ng-template #t13>
        Template for foo between 1 and 3
    </ng-template>
    <!-- If Else Statement -->
    <ng-template #t46>
        Template for foo between 4 and 6
    </ng-template>
    <!-- Else Statement -->
    <ng-template #t7>
        Template for foo greater than 7
    </ng-template>
    

Note: You can choose any format, but notice every code has own problems

Sina Lotfi
  • 3,044
  • 1
  • 23
  • 30
24

Or maybe just use conditional chains with ternary operator. if … else if … else if … else chain.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Conditional_Operator#Conditional_chains

<ng-container [ngTemplateOutlet]="isFirst ? first : isSecond ? second : third"></ng-container>

<ng-template #first></ng-template>
<ng-template #second></ng-template>
<ng-template #third></ng-template>

I like this aproach better.

Gerald Hughes
  • 5,771
  • 20
  • 73
  • 131
17

To avoid nesting and ngSwitch, there is also this possibility, which leverages the way logical operators work in Javascript:

<ng-container *ngIf="foo === 1; then first; else (foo === 2 && second) || (foo === 3 && third)"></ng-container>
  <ng-template #first>First</ng-template>
  <ng-template #second>Second</ng-template>
  <ng-template #third>Third</ng-template>
Max21
  • 295
  • 3
  • 6
5

you don't need to use *ngIf if you use ng-container

<ng-container [ngTemplateOutlet]="myTemplate === 'first' ? first : myTemplate === 
   'second' ? second : third"></ng-container>

  <ng-template #first>first</ng-template>
  <ng-template #second>second</ng-template>
  <ng-template #third>third</ng-template>
nicolas
  • 84
  • 1
  • 2
1

<ion-row *ngIf="cat === 1;else second"></ion-row>
<ng-template #second>
    <ion-row *ngIf="cat === 2;else third"></ion-row>
</ng-template>
<ng-template #third>

</ng-template>

Angular is already using ng-template under the hood in many of the structural directives that we use all the time: ngIf, ngFor and ngSwitch.

> What is ng-template in Angular

https://www.angularjswiki.com/angular/what-is-ng-template-in-angular/

Supriya
  • 481
  • 5
  • 5
1

I came a cross this type of situation *ngIf elseIf else and I solved using ng-template, Hope the following snippet may depicts briefly,

I have a form control named "NIC" and need to show one error message at a time when the form control invalid.

form: FormGroup = new FormGroup({
    NIC: new FormControl('', [Validators.required, Validators.minLength(10), Validators.maxLength(10), Validators.pattern("^[0-9]*$")])
  });

Template

<mat-form-field appearance="standard">
    <mat-label>NIC Number</mat-label>
    <input matInput placeholder="Enter NIC no" formControlName="NIC">
    <mat-error *ngIf="form.controls['NIC'].errors?.required; else minvalue">This field is mandatory.
    </mat-error>

    <ng-template #minvalue>
        <mat-error *ngIf="form.controls['NIC'].errors?.minlength; else maxvalue">Minimum 10 charactors
            needed.
        </mat-error>
    </ng-template>

    <ng-template #maxvalue>
        <mat-error *ngIf="form.controls['NIC'].errors?.maxLength; else numericonly">Maximum 10
            charactors allowed.
        </mat-error>
    </ng-template>

    <ng-template #numericonly>
        <mat-error *ngIf="form.controls['NIC'].errors?.pattern">
            Numeric characters only.
        </mat-error>
    </ng-template>

</mat-form-field>
Azad
  • 5,144
  • 4
  • 28
  • 56
1

If you have a straightforward case in which some variable can take several values (for example, foo is of 1 | 2 | 3 type) then just use the plain ngSwitch:

<ng-container [ngSwitch]="foo">
    <div *ngSwitchCase="1">First</div>
    <div *ngSwitchCase="2">Second</div>
    <div *ngSwitchCase="3">Third</div>
</ng-container>

However, if you need a more sophisticated if-else logic it may be better and clearer to describe it inside a component function making use of a set of the needed states:

getLandformType(): 'continent' | 'island' | 'peninsula' {
  if(this.pieceOfLand.bigEnough){
    return 'continent';
  }
  else if(this.pieceOfLand.surroundedByWater){
    return 'island';
  }
  return 'peninsula';
}

which, again, can be handled through ngSwitch:

<ng-container [ngSwitch]="getLandformType()">
  <div *ngSwitchCase="'continent'">Continent</div>
  <div *ngSwitchCase="'island'">Island</div>
  <div *ngSwitchCase="'peninsula'">Peninsula</div>
</ng-container>

This approach also ensures that only one option can win at once, in contrast to that with three different *ngIf (without elses) blocks.

Ilya Loskutov
  • 1,967
  • 2
  • 20
  • 34
0

Alternatively, you can also use *ngIf-then-else and ternary operator:

<ng-container *ngIf="isFirst; then first; else (isSecond ? second : third)"></ng-container>

<ng-template #first>First</ng-template>
<ng-template #second>Second</ng-template>
<ng-template #third>Third</ng-template>
icaru12
  • 1,522
  • 16
  • 21
0

In Angular, you can use the ngSwitch directive to achieve the functionality of having multiple cases in an *ngIf statement. Here's an example:

<div [ngSwitch]="foo">
  <ng-template [ngSwitchCase]="1">First</ng-template>
  <ng-template [ngSwitchCase]="2">Second</ng-template>
  <ng-template [ngSwitchCase]="3">Third</ng-template>
  <ng-template ngSwitchDefault>Default</ng-template>
</div>
jignesh kumar
  • 409
  • 1
  • 4
  • 6
-1

You can also use this old trick for converting complex if/then/else blocks into a slightly cleaner switch statement:

<div [ngSwitch]="true">
    <button (click)="foo=(++foo%3)+1">Switch!</button>

    <div *ngSwitchCase="foo === 1">one</div>
    <div *ngSwitchCase="foo === 2">two</div>
    <div *ngSwitchCase="foo === 3">three</div>
</div>
Michael Payne
  • 534
  • 5
  • 13