3

I want to change img tag src based on a condition. I am using ternary operator right now; I want to ask is there a way to use ngSwitch instead (WITHOUT REPEATING the img tag). Here is my code:

<div>
  <img height='26' width='22' [src]="
       bank.bankName.includes('a') ? 'assets/images/a.png' :
       bank.bankName.includes('b') ? 'assets/images/b.png' :
       bank.bankName.includes('c') ? 'assets/images/c.png' :
       bank.bankName.includes('d') ? 'assets/images/d.png' : ''
  " />
</div> 
Qiimiia
  • 510
  • 6
  • 16

5 Answers5

1

I would create a pipe, so you write once the code and then just add it to any HTML file, especially if you are going to use this feature in more components. Moreover, it is easier to modify/extend in the future, as you only have to modify in one place.

I leave HERE a stackblitz with the code, but it would be just something like this:

A) For using it in any HTML file (just add | bankNameImagePipe):

<img height='26' width='22' [src]="bank.bankName | bankNameImagePipe" />

B) Pipe file:

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

@Pipe({
  name: 'bankNameImagePipe',
})
export class BankNameImagePipe implements PipeTransform {

  transform(value: string): string {

    let urlBankImg: string = 'assets/images/';

    switch (value) {
      case 'a':
        urlBankImg+= 'a.png';
        break;
      case 'b':
        urlBankImg+= 'b.png';
        break;
      case 'c':
        urlBankImg+= 'c.png';
        break;
      case 'd':
        urlBanckImg+= 'd.png';
        break;

      default:
        urlBankImg= 'default.png'; // You can add a 'default' image url here
        break;
    }

    return urlBankImg;
  }
}

NOTE: I assume that bank.bankName will be a string and not an array. If it were not a string, you would have to change the pipe appropriately.

HOW TO CREATE THE PIPE? You only need to type this command in your console/bash to create a pipe:

ng g pipe pipes/bankNameImage

ng means Angular CLI g means Generate pipes means the folder where you want the pipe to be bankNameImage means the pipe name (the one to be used for using the pipeline in HTML)

Then, you only have to fill the empty template code that this command will have created in the file bank-name-image.pipe.ts with the code I provided above.

1

I'll try answering the question (Instead of telling you what would i do). No, you can't use ngSwitch instead without repeating the whole img tag. Each ngSwitchCase will display/hide an element. That's how the ngSwitch syntax works:

https://angular.io/api/common/NgSwitchCase

So, the syntax for your labelling with ngSwitch would be something like:

  <ng-container [ngSwitch]="bank.bankName">
    <img *ngSwitchCase="'a'" src="/assets/a.svg" />
    <img *ngSwitchCase="'b'" src="/assets/b.svg" />
    <img *ngSwitchCase="'c'" src="/assets/c.svg" />
    <img *ngSwitchCase="'d'" src="/assets/d.svg" />
  </ng-container>

I've left a crude example here:

https://stackblitz.com/edit/angular-ivy-lmfttq?file=src/app/hello.component.html

That is how ngSwitch works in Angular templates.

0

Writing code in a chain of ternary operators is never really a good move, especially in HTML templates. The switch is fine and if you really want to avoid it, you can simply write this code in component.ts file and set an public imageSrc = '' named peropty, compute the result and assign it.

<div>
  <img height='26' width='22' [src]="imageSrc" />
</div> 
vaira
  • 2,191
  • 1
  • 10
  • 15
  • I don't really want to get it involved in ts file – Qiimiia Nov 30 '21 at 06:40
  • 1
    Actually i would rather strongly suggest doing this in ts file where most logic should be kept, if you specifically want to ignore creating multiple ngswtich image tags – vaira Nov 30 '21 at 16:17
0

You can do this in the TS file like this:

Reason for not doing in HTML: Its not a good practice and also once the view (HTML Page) is loaded, the manipulations should be rendered from the component.ts file. Not in the HTML

// In component.ts file, you can create a method which returns a string: 

@Component({
  selector: 'your-app-selector',
  templateUrl: './your-app.component.html',
  styleUrls: ['./your-app.component.scss']
})
export class YourComponent implements OnInit {
 imagePath: string = '';

constructor(){}

ngOnInit(): void {
 this.imagePath = this.returnImagePath(bank.bankName);
}

returnImagePath(bankName: string): string {
  let pathOfImage: string = 'assets/images/';
  switch (bankName) {
      case bankName.includes('a'):
        pathOfImage += 'a.png';
        break;
      case bankName.includes('b'):
        pathOfImage += 'b.png';
        break;
      case bankName.includes('c'):
        pathOfImage += 'c.png';
        break;
      case bankName.includes('d'):
        pathOfImage += 'd.png';
        break;
      default:
        pathOfImage += ''; 
        break;
    }
  }
  return pathOfImage;
}

// YOUR HTML WOULD TURN INTO THIS ONE LINER
<img height='26' width='22' [src]="imagePath" />

This way you can avoid pipes, unnecessary HTML checkings too.

Srikar Phani Kumar M
  • 1,069
  • 1
  • 3
  • 8
0

I would personally recommend to do all the work in your ts file instead of piling up so many conditions in the html file.

html file:

<div>
  <img height='26' width='22' [src]="getImage(bank.bankName)" />
</div>

ts file:

getImage(value){
  let imagePath='assets/images/';
  
  switch(value){
   case (value.indexOf('a')!=-1): imagePath+= 'a.png';
    break;
   case (value.indexOf('b')!=-1): imagePath+= 'b.png';
    break;
   case (value.indexOf('c')!=-1): imagePath+= 'c.png';
    break;
   case (value.indexOf('d')!=-1): imagePath+= 'd.png';
    break;
   default: // can add default image as per your requirement
  }
  return imagePath;
}
 
Mukul_Vashistha
  • 106
  • 1
  • 5