154

In php and java we can do

case 1:
case 2:
   echo "something";

so that when the value is 1 or 2 "something" will be printed on the screen, i am building an angular application i am doing something like the below

<div [ngSwitch]="data.type">
  <div *ngSwitchCase="'multi-choice'">FORM 1</div>
  <div *ngSwitchCase="'singe-choice'">FORM 1</div>
  <div *ngSwitchCase="'range'">FORM 2</div>
</div>

The form which is used for single choice can be used for mutiple choice , but i tried something like below to make it more organisable

<div [ngSwitch]="data.type">
  <div *ngSwitchCase="'multi-choice' || 'singe-choice'">FORM 1</div>
</div>

My bad luck it didnt work, can anyone suggest the better way to do this.

1

12 Answers 12

219

(Un)fortunately you can‘t; the ngSwitch is quite “dumb” if you look at the source code: it‘s just a === between the case value and the switch value. You have two options, but both of them are far from great.

Option 1 is using the directive *ngSwitchDefault, but this will only work if all your multiple cases are FORM 1:

<div [ngSwitch]="data.type">
  <div *ngSwitchDefault>FORM 1</div>
  <div *ngSwitchCase="'range'">FORM 2</div>
</div>

The other option, which is quite verbose, is doing something like this:

<div [ngSwitch]="data.type">
  <div *ngSwitchCase="data.type === 'multi-choice' || data.type === 'singe-choice' ? data.type : '' ">FORM 1</div>
  <div *ngSwitchCase="'range'">FORM 2</div>
</div>
Sign up to request clarification or add additional context in comments.

7 Comments

I am going for the second because the default is meaning something else, thank you for this idea!
I'm throwing this out there, if someone needs to or a Switch Case ... maybe you need a *ngIf instead of a switch :\
for some unknown reason, this is not working in angular v6. however the 3rd answer is working. (by MoshMage)
Can be improved: *ngSwitchCase="['multi-choice', 'singe-choice'].includes(data.type) ? data.type : '' "
I fixed the problem using second option. I do not understand why the first does not work. Can you have a look at Using extra parameter in ngSwitchCase please? Regards...
|
110

You can use ngTemplateOutlet to implement this:

<ng-container [ngSwitch]="variable">
    <ng-container *ngSwitchCase="1">
        <ng-container *ngTemplateOutlet="form1"></ng-container>
    </ng-container>
    <ng-container *ngSwitchCase="2">
        <ng-container *ngTemplateOutlet="form1"></ng-container>
    </ng-container>
    <ng-container *ngSwitchCase="3">FORM 2</ng-container>
    <ng-container *ngSwitchDefault>FORM 3</ng-container>
    <ng-template #form1>FORM 1</ng-template>
</ng-container>

Update

While Angular still considering such feature, there is jonrimmer's switch-cases.directive.ts. Usage example:

<ng-container [ngSwitch]="variable">
    <ng-container *jrSwitchCases="[1, 2]">FORM 1</ng-container>
    <ng-container *ngSwitchCase="3">FORM 2</ng-container>
    <ng-container *ngSwitchDefault>FORM 3</ng-container>
</ng-container>

4 Comments

This is by far the cleanest and least hacky solution. It is also hinted to in the docs: "Each switch-case statement contains an in-line HTML template or template reference"
One word of warning: the content of #form1 will re-render between switchCase 1 and 2. For many this won't matter, but if the component is complex, then for now you're better off with an *ngIf.
What will happen when someone adds a type=5 ? A default is a very bad idea here. Why is the value 4 more important than the values 1 and 2? I have seen endless bugs resulting from this pattern by too many developers.
Just FYI, you can reduce that template by nearly 2 times as you can provide the template as an input too: <ng-container *ngSwitchCase="1" [ngTemplateOutlet]="form1"> which will let you avoid the nested ng-container
84

You can also use the following, which is a lot more flexible. You can then put anything that evaluates to boolean as the *ngSwitchCase value.

<div [ngSwitch]="true">
    <div *ngSwitchCase="data.type === 'multi-choice' || data.type === 'singe-choice'">FORM 1</div>
    <div *ngSwitchCase="data.type === 'range'">FORM 2</div>
    <div *ngSwitchDefault>FORM 3</div>
</div>

The advantage this has over using *ngIf blocks is that you can still specify a default.

5 Comments

This one that worked for me, but it is strange to switch a 'true' statement.
@GuilhermeSampaio strange !== bad. Such approach can be very useful sometimes.
@Tomek yes! It was useful for me! :D
The problem is you have a default (another name for a try/catch/continue)
The new @if syntax can easily let you have an else case to cover the default, I'd really argue to prefer now the new syntax over a "hacked" ngSwitch angular.dev/api/core/@if
33

Here's a variation that combines Fabio's second answer with brian3kb's to produce a more condensed solution without obfuscating meaning.

If there are multiple matches for a case it uses array.includes() instead of comparing each option individually.

It is especially useful if there are more than two matches as it will be much more condensed relative to the accepted answer.

<div [ngSwitch]="data.type">
   <div *ngSwitchCase="['multi-choice', 'singe-choice'].includes(data.type) ? data.type : ''">FORM 1</div>
   <div *ngSwitchCase="'range'">FORM 2</div>
   <div *ngSwitchDefault>FORM 3</div>
</div>

If the matches happen to be in a variable, you can use array.indexOf() to avoid the use of the conditional ternary operator.

<div [ngSwitch]="data.type">
  <div *ngSwitchCase="matches[matches.indexOf(data.type)]">FORM 1</div>
  <!-- ... -->
</div>

Comments

18

Like MoshMage suggested, I ended up using an *ngIf to handle this for the components that handled several of the options:

 *ngIf="['Transformation', 'Field Mapping', 'Filter'].includes(selectedWorkflow.type)"

1 Comment

While this reads nicely, be aware that you it'd be a good idea to have the change detection strategy set to OnPush for this component and to make sure that it's not a component that is going to be refresh very often. During each change detection cycle, you will create a new array and 3 new strings and go through the array to check if the value is in here. I know we shouldn't do too much micro optimisations either, but just make sure this component isn't refreshed too often
17

Greetings from the year 2024! Angular 17 now has new control flow statements that include @switch so answers with the *ngSwitch directive will be less and less relevant as time goes on.

Unfortunately, this is still an issue despite the new syntax and it being 8 years after this question was originally asked. The new syntax doesn't support multiple cases, but this is easily overcome by switching on true and having an regular conditional statement. This is very similar to the solution originally proposed by @escapism.

@switch (true) { 
  @case (data.type === 'single-choice' || data.type === 'multi-choice') {
    <div>FORM 1</div>
  } 
  @default {
    <div>FORM 2</div>
  }
}

And here's a variation based on my original answer. The above solution is better unless you really want to be explicit on the expression being "switched" on.

@switch (data.type) { 
  @case (['multi-choice', 'single-choice'].includes(data.type) && data.type) {
    <div>FORM 1</div>
  } 
  @default {
    <div>FORM 2</div>
  }
}

1 Comment

Although I'm not going to use it, it's still inspirational and also addresses what I was looking for, an alternative. Just upvoted, thank you.
12

It could be achieved using the ngTemplateOutlet directive:

<ng-container [ngSwitch]="colour">
    <ng-container *ngSwitchCase="'green'">:)</ng-container>
    <ng-container *ngSwitchCase="'yellow'">;)</ng-container>
    <ng-container *ngSwitchCase="'black'" [ngTemplateOutlet]="sad"></ng-container>
    <ng-container *ngSwitchCase="'darkgrey'" [ngTemplateOutlet]="sad"></ng-container>
</ng-container>

<ng-template #sad>:(</ng-template>

1 Comment

Why sad, not glad?
5

use ngFor:

<ng-container [ngSwitch]="column">
  <ng-container *ngFor="let numeric of ['case1', 'case2']">
    <ng-container *ngSwitchCase="numeric">
      {{ element[column] | currency }}
    </ng-container>
  </ng-container>
</ng-container>

1 Comment

Hi, Welcome to Stack Overflow. As explained in the tour, this site is a repository of useful questions and their answers. Your answer is (included in)/(very similar to) [this answer](link/to/answer), and not very useful since it does not add any new value or information. Please avoid writing duplicate answers. Either edit your answer to add value or delete it altogether; this will ensure all questions and answers on the site remain useful and not scattered/duplicated.
3

Here's how I would do it:

In your .component.ts:

getFormType(type: string) {
  switch(type) {
    case 'singe-choice':
    case 'multi-choice':
      return 'singe-choice|multi-choice'
    default:
      return type;
  }
}

Then, in your template file, you can do something like this:

<div [ngSwitch]="getFormType(data.type)">
   <div *ngSwitchCase="'singe-choice|multi-choice'">FORM 1</div>
   <div *ngSwitchCase="'range'">FORM 2</div>
   <div *ngSwitchDefault>FORM 3</div>
</div>

Watch out for typos though...

Comments

2

The Fabio Antunes's second answer, but with a pipe:

import { Pipe, PipeTransform } from '@angular/core';

@Pipe({
  name: 'multiSwitchCase',
})
export class MultiSwitchCasePipe implements PipeTransform {
  transform<T = any>(cases: T[], value: T): T {
    return cases.includes(value) ? value : cases[0];
  }
}
<div [ngSwitch]="data.type">
  <div *ngSwitchCase="['multi-choice', 'singe-choice'] | multiSwitchCase: data.type">
    FORM 1
  </div>
</div>

Comments

1

Please try ng-switch-when-separator="|" in ng-switch

<div ng-switch="temp">
    <div ng-switch-when="1|2" ng-switch-when-separator="|"> echo "something"</div>
</div>

1 Comment

Please note that this directive is a feature of AngularJS (aka v1), not Angular (aka v2 or higher). Even though it's been requested in the past, it isn't yet provided on any version from Angular 2 till Angular 9 (at the date of this comment).
-1

Swtich Case in Angular Html

@switch(account.membershipStatus) {
    @case ('gold') {
        <span class="badge-gold"> Gold </span>
    }
    @case ('silver') {
        <span class="badge-silver"> Silver </span>
    }
    @case ('platinum') {
        <span class="badge-platinum"> Platinum </span>
    }
    @default {
        <span class="badge-default"> -- </span>     
    }
}

You Can Even Try ifElse

@if(account.membershipStatus === 'gold') {
        <span class="badge-gold"> Gold </span>
} @else if(account.membershipStatus === 'silver') {
        <span class="badge-silver"> Silver </span>
} @else if(account.membershipStatus === 'platinum') {
        <span class="badge-platinum"> Platinum </span>
} 

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.