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
rxjsby default. We can implement the power ofObservablesto solve this problem.We can implement something like
ObsevablesObservableDefine 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
fromandofoperators fromrxjsDefine another observable to track industry id
Next step is to define a way to track the selected industry. I will use a
BehaviorSubjectthat will emit a value on initial load and every time we call thenext()function on theSubjectCombine the two
ObsevablesNext we need to combine the two
Observables. We will usecombineLatestfromrxjsFrom the official documentationWe are piping the
Observablestream and usingmapoperator fromrxjs/operatorsto transform the dataAlmost Done, Subscribe to the resultant
ObservableWe will the
asyncpipe 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
SubjectWith the above approach, angular change detection will only be triggered when
changeSelectedId ()function is called