In below snippet, I am calling the same function named isSiteAlreadyAdded(site.id) for 3 different attribute. Is there any way so I can store the value for particular option tag and use it in for given options attribute?
<div >
<select style="width: 100%;" id="sites" [(ngModel)]="site" name="sites" #sites="ngModel" required>
<option [ngValue]="null" selected>Select Site</option>
<option *ngFor="let site of sitesToAdd" [ngValue]="site" data-toggle="tooltip" data-placement="top" title="{{isSiteAlreadyAdded(site.id) ? 'Site is already added.':''}}" [ngClass]="{'alert alert-secondary': isSiteAlreadyAdded(site.id)}" [disabled] = "isSiteAlreadyAdded(site.id)">{{site.name}}</option>
</select>
</div>
CodePudding user response:
As described in the linked post from @dan vid, function calls within the template are a bad practice because they will be executed with each change detection tick.
So, either you can use a pipe or you pre-calculates the respective value.
Pipe
If you're using a pipe you'd still calculate the values multiple times but only if the input value of the pipe changes, which reduces the times of re-calculation by a lot compared to function calls in the template.
A basic pipe would look like this:
@Pipe({ name: 'isAlreadyActive' })
export class IsAlreadyActivePipe implements PipeTransform {
transform(id: string): boolean { // <- or any other return type instead of boolean
// Implement your check and return the result
}
}
And the call in your case would look like this:
<option
...
title="{{ site.id | isAlreadyActive ? 'Site is already added.': '' }}"
...
>
{{site.name}}
</option>
You'll find more about pipe here.
Storing a conditional result in a variable
There is also the possibility to store the pipe return value in a variable (see here).
This would look like this:
<ng-container *ngIf="site.id | isAlreadyActive as isActive">
<option
...
title="{{ isActive ? 'Site is already added.': '' }}"
...
>
{{site.name}}
</option>
</ng-container>
In this example, we've stored the result in isActive
and your calculation would only be executed one time but as soon as the return value is falsy
the content of the *ngIf
isn't shown.
In you case, for example, you could return instead of a simply boolean and object containing a boolean, e.g., { isActive: returnValue }
. That way your return value would be truthy
and the content would be shown.
Pre-Calculation
The other option would be to pre-calculate the value in your component and assign the value to site.isActive
as example. That way you only have one calculation, which is also better than a function call from the template.