5

Seven years ago, this question has been asked already for Angular's old ngSwitch/ *ngSwitchCase syntax. Updating our templates to the nice new syntax, I step across the same question again: What is the best way to avoid duplicated parts in situations where several cases share the same UI?

The Angular docs state that @switch does not support fallthrough (which I regard as a good choice to avoid all errors with missing breaks). But as far as I see, they didn't add something to give a list of options to a single @case?

So the only way is to use <ng-template>? E.g.

  @switch (type) {
    @case ('type1') { ... }
    <ng-template #shared>Some UI shared for several cases</ng-template>
    @case ('type2') { <ng-container *ngTemplateOutlet="shared"/> }
    @case ('type3') { <ng-container *ngTemplateOutlet="shared"/> }
    @case ('type4') { ... }

Or, use @default and @if inside? Not sure which way would be better to understand and maintain.

2
  • 1
    IMHO this is a problem with switch (type) where you switch on groups, Maybe you need to switch on another variable that distinguishes the cases. Commented Jan 23, 2024 at 11:49
  • 1
    That's actually the cleanest solution to first map my type to a computed and aggregated type and use this inside the switch, thanks!! @grenobnik, Do you want to propose this as an answer as well? Commented Jan 26, 2024 at 12:16

3 Answers 3

4

You can use a ternary operator in your @case, it is far from great and it is verbose but you can have many conditions in a simple @case.

Example:

@switch (type) {
        @case ('type1') { <div>Hi from type1</div> }
        @case (type === 'type2' || type === 'type3' ? type : '') { <ng-template #shared>Some UI shared for several cases</ng-template> }
        @case ('type4') { <div>Hi from type4</div> }
Sign up to request clarification or add additional context in comments.

4 Comments

also an interesting option. I agree with 'far from great' ... would be cool if Angular would add some support for this case.
You can use a logical OR (||) directly in control-flow cases as follows @case ('type1' || 'type2' || null ) { ... }. This may have been in a more recent update.
The logical OR returns the first truthy value from the OR-chain. In this example, the @case will always evaluate against 'type1'
@Alex, I'm not seeing that to work.
3

We can use the classic switch(true) followed by conditionals with multiple checks, to support checking for two scenarios in one case block, I hope that is what you are looking for.

If we set switch to true, it will let us not do a strict string check, so for each case we can chain conditions like @case (type === 'type2' || type === 'type3') { <ng-container *ngTemplateOutlet="shared"/> } and enable code reusability. Please find below working example!

import { CommonModule } from '@angular/common';
import { Component } from '@angular/core';
import { bootstrapApplication } from '@angular/platform-browser';
import 'zone.js';

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [CommonModule],
  template: `
    @switch (true) {
    @case (type === 'type1') { <h1>Hi Type 1</h1> }
    @case (type === 'type2' || type === 'type3') { <ng-container *ngTemplateOutlet="shared"/> }
    @case (type === 'type4') { <h1>Hi Type 4</h1> }
    }

    <ng-template #shared><h1>Some UI shared for several cases (Type 2 or Type3)</h1></ng-template>
  <hr/>
  <br/>
    <button (click)="type = 'type1'">set type1</button>
    <button (click)="type = 'type2'">set type2</button>
    <button (click)="type = 'type3'">set type3</button>
    <button (click)="type = 'type4'">set type4</button>
  `,
})
export class App {
  type = 'type2';
}

bootstrapApplication(App);

stackblitz

Comments

1

It might lead to cleaner code using the switch statement for actual distinguished cases, and therefore it is better to map the switch variable accordingly in ts file (e.g. using some computed signal).

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.