I'm currently building a table which has a particular column where I need to proccess de data a bit to get the actual value I want to display; the value in the row's object is an ID number, so I then have to look for that ID inside an array of objects I have in a variable.
Like this:
findIndustry(industry: string) {
if (this.industries.find(x => x._id === parseInt(industry, 10))) {
const industryResult = this.industries.find(x => x._id === parseInt(industry, 10));
return `${industryResult.category} | ${industryResult.subcategory}`;
}
return '(Not Set)';
}
After getting the result I can just display it on the table like this:
<ng-container matColumnDef="parentName">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Industry </th>
<td mat-cell *matCellDef="let client" class="industry-cell">{{ findIndustry(client.industry) }}</td>
</ng-container>
But now comes the issue; based on the returned value, I want to show a title
attribute, and I also want to add an ngClass
directive to show the text in grey color when (Not Set)
is the value:
<ng-container matColumnDef="parentName">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Industry </th>
<td mat-cell *matCellDef="let client"
[ngClass]="findIndustry(client.industry) === '(Not Set)' ? 'text-muted' : ''"
class="industry-cell"
[title]="findIndustry(client.industry)">{{ findIndustry(client.industry) }}</td>
</ng-container>
I've read that using function calls in Angular templates is a bad idea, since it would run the function on every change detection, which can be a lot of times; I'm wondering what would be an efficient way to avoid running the function so many times, or even better just avoid using the function at all; I do need that same value to apply different properties, that's the only reason I'm using it on every directive and attribute.
As you have stated, having a function in your html is a very bad idea...
Below is an article about how a function is called in the html
Reactive Programming to the rescue
Angular comes preinstalled with
rxjs
by default. We can implement the power ofObservables
to solve this problem.We can implement something like
Obsevables
Observable
Define an observable with the data
On many occasions this would be simply a response from an http request
We can also generate an observable using
from
andof
operators fromrxjs
Define another observable to track industry id
Next step is to define a way to track the selected industry. I will use a
BehaviorSubject
that will emit a value on initial load and every time we call thenext()
function on theSubject
Combine the two
Obsevables
Next we need to combine the two
Observables
. We will usecombineLatest
fromrxjs
From the official documentationWe are piping the
Observable
stream and usingmap
operator fromrxjs/operators
to transform the dataAlmost Done, Subscribe to the resultant
Observable
We will the
async
pipe to perform this purposeFinally... Define a way to trigger change in the industry id
To trigger change of the selected item, we simply call the next method on the
Subject
With the above approach, angular change detection will only be triggered when
changeSelectedId ()
function is called