I have the next code:
this.currency$ = combineLatest([
this.currency.valueChanges, // Currency ID Form Control (selected currency id)
this.currencies$, // A list of currencies, that is loaded from backend
]).pipe(
map((result: [number, Currency[]]) => {
// todo: optimize - do not loop over all, stop when found
let currencyName = '';
if (result[1]) {
result[1].forEach((currency: Currency) => {
if (currency.id === this.currency.value) {
currencyName = currency.name;
}
});
}
return currencyName;
})
);
The problem is, when I subscribe in the template to the currency$ observable, using the | async pipe - The calculation (determination of the currency name) happens twice.
What is a good solution, to calculate it only once and on every subscription, emit already calculated currency name? Of course I could add a component variable and preserve name there, but I would like to use observables, so the component should not have it's own state...
You can avoid this by using shareReplay Operator https://www.learnrxjs.io/learn-rxjs/operators/multicasting/sharereplay to share the source and it the calculation will be done just once
import { map, shareReplay } from 'rxjs/operators';
...
this.currency$ = combineLatest([
this.currency.valueChanges, // Currency ID Form Control (selected currency id)
this.currencies$, // A list of currencies, that is loaded from backend
]).pipe(
map((result: [number, Currency[]]) => {
// todo: optimize - do not loop over all, stop when found
let currencyName = '';
if (result[1]) {
result[1].forEach((currency: Currency) => {
if (currency.id === this.currency.value) {
currencyName = currency.name;
}
});
}
return currencyName;
}),
shareReplay() // here
);
on this other hand avoid using multiple async pipe on your template, you can use an ng-container to set the value of your async pipe result to a variable and use it everywhere in your template
<ng-container *ngIf="currency$ | async as curency">
// use currency here
</ng-container>