0

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 class="template-form-input-container">
          <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>
3
  • 1
    In controller pre-calculate this value for site.disable = this.isSiteAlreadyAdded(site.id) Commented Dec 22, 2021 at 7:44
  • 7
    Read this article about Function Calls medium.com/showpad-engineering/… Commented Dec 22, 2021 at 7:45
  • Hi @danvid I went through this, but I am still not sure, how to pass parameter? Commented Dec 22, 2021 at 8:08

1 Answer 1

2

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.

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you so much for this answer. It gave me fair idea, and the issue got solved. I used the pipe approach.

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.