Home > Software design >  How to prevent using function calls in Angular template expressions
How to prevent using function calls in Angular template expressions

Time:11-23

I have a child component that gets a year list from parent, and needs to style an element if that list contains the current year.

The child ts:

export class ChildComponent implements OnInit {
  @Input() listYears: Array<number> = [];
  year = 2022;
  constructor() { }

  ngOnInit(): void {
  }

  existInList() {
    return this.listYears.find(x => x === this.year);
  }

}

the child html:

<div [style.background-color]="existInList() ? 'red' :  'blue' ">
  </div>

and the parent html:

<app-child [listYears]="[2022]"></app-child>

Because the condition for the style uses a method, and the recommendation is to prevent using function calls in Angular template expressions (never use function calls in Angular template) so how can I achive this without a function call?

I assume that inserting the condition within the template instead of in ts, like this:


<div [style.background-color]="listYears.find(x => x === year) ? 'red' :  'blue' ">
  </div>

does not matter for performance. Am I wrong? If not - what's the write way?

Thanks

CodePudding user response:

Your solution is, of course, to use an Angular Pipe. Here is a link to docs.

Pipes are maintained exactly for this, to transform data on template in a smart and performance considered way.

Your pipe will look like this:

@Pipe({
    name: 'existInList'
})
export class ExistInListPipe implements PipeTransform {
    transform(listYears: number[], year: number): string {
        return listYears.find((x) => x === year) ? 'red' :  'blue';
    }
}

And in your template:

<div [style.background-color]="listYears | existInList : year">
  </div>

CodePudding user response:

I recommend a setter method along with HostBinding.

@Component({
  selector: 'hello',
  template: `<h1>Hello!</h1>`,
  styles: [`h1 { font-family: Lato; }`],
})
export class HelloComponent {
  private _listYears: number[];
  yearToStyle: number = 2022;

  @HostBinding('style.color')
  background: string;

  @Input()
  set listYears(value: number[]) {
    this._listYears = value;

    this.background = value.includes(this.yearToStyle) ? 'red' : 'blue';
  }
}

Stackblitz: https://stackblitz.com/edit/angular-ivy-4hgtdn?file=src/app/hello.component.ts

  • Related