Home > other >  Avoid functions in template in case of ul list
Avoid functions in template in case of ul list

Time:12-05

How to avoid using function in the template in this case (simplified)?

post.component.ts

import { Details, Status } from 'models';

export class PostComponent implements OnInit {
  @Input() pckgs: Details[];
  //...

  myFunc2(pckg: Details) {
    return pckg.status === Status.P ? 'processing' : pckg.status === Status.D ? 'finished' : '';
  }  
}

post.component.html

<ul>
  <li *ngFor="let pckg of pckgs; trackBy: trackId">
    <span [ngClass]="myFunc1(pckg)">{{myFunc2(pckg)}}</span>
  </li>
</ul>

I believe it can be similar to method called in ngFor gets trigger for multiple times somehow , but in that example it's not ngFor="let item of items".

CodePudding user response:

Use a pure pipe.

HTML

<ul>
  <li *ngFor="let pckg of pckgs; trackBy: trackId">
    <span [ngClass]="myFunc1(pckg)">{{ pckg | statusDisplay }}</span>
  </li>
</ul>

pipe

@Pipe({ name: 'statusDisplay', pure: true })
export class StatusDisplayPipe implements PipeTransform {
  transform(pckg: Details): string {
    return pckg.status === Status.P ? 'processing' : pckg.status === Status.D ? 'finished' : '';
  }
}

CodePudding user response:

You could also "enrich" or adapt your @Input() pckgs: Details[] using a setter.

type PackageDetail = Details & { readableStatus: string };


public packages: Array<PackageDetail> = [];

@Input() set pckgs(pckgs: Details[]) {
   this.packages = pckgs.map((p)=> {
   return  {...p, ...{readableStatus: p.status === Status.P ? 'processing' : p.status === Status.D ? 'finished' : ''}} as PackageDetail;});
}

Btw, you don't have to do it in the component, perhaps you cold have some sort of mapper already in place so that the PostComponent simply received what it needs.

Another option could be to use a memoized function (which is what Angular does with the pure pipe behind the scenes) I saw this one in a tweet by Pawel Kozlowski :)

  • Related