ChatGPT解决这个技术问题 Extra ChatGPT

*ngIf else if in template

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?

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.

C
CornelC

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>

This was the better solution for me. My conditions were based on multiple variables and more than one were capable of being true at the same time.
Can't we use like <ng-template #second *ngIf="foo === 2;else third">
When chaining ngIf, the which is addressed by a previous else does not support another ngIf. A nested tag allows to insert the next condition.
D
Dylan

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


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.
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.
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 */ }
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.
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.
g
goat

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...


S
Sina Lotfi

You can use multiple way based on sitaution:

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

First Number
Second Number
Third Number
Other Number
First Number Second Number Third Number
Daniel String
David String
Alex String
Other String
Alex String David String Daniel String Above not suitable for if elseif else codes and dynamic codes, you can use below code: Template for foo between 1 and 3 Template for foo between 4 and 6 Template for foo greater than 7

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


IMO 2. should read *ngIf="foo >= 7; then t7" instead of ... else t7.
I think just two lines with the second one being foo >= 4 && foo <= 6; then t46; else t7 should work.
G
Gerald Hughes

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.


M
Max21

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>

n
nicolas

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>

S
Supriya

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/


A
Azad

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>

M
Michael Payne

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>

The *ngSwitchDefault directive would provide an "else" case.
This approach is one the OP mentions in their question, and says they don't like.