This is a pattern I frequently find myself in and I'm not sure why or what the right way to achieve my goals is.
I need a number
value which many calculations are dependent upon, but this value needs to be retrieved from an observable.
I'm using a get method in the service that my component can call upon, but I always struggle to find the correct pattern to achieve this.
My service method:
getMarketCap(company: Company): number {
combineLatest([
this.getPrevDayClose(company.ticker),
this.getCurrDayLastPrice(company.ticker),
this.getWsLastPrice(company.ticker)
]).pipe(
tap(([prevDayClose, currDayLastPrice, wsLastPrice]) => {
if (wsLastPrice) {
this.price = wsLastPrice;
} else if (currDayLastPrice) {
this.price = currDayLastPrice;
} else {
this.price = prevDayClose;
}
return this.price * this.getSharesOutstanding(company);
})
);
}
This won't work because the return which includes the value I want is inside the tap
.
My component is a list of companies and I simply call this.service.getMarketCap(company)
in ngOnInit()
for each one. Is there a simple way to get the value of this.price
out of there after being set, so it can be consumed by other calculation methods in the service?
I've done something like this before with component methods, but I was able to set a variable at the component-level since it was only ever setting for one company at a time.
Is the service the wrong place for this logic?
Is there a simple way to get the value of
this.price
out of there after being set, so it can be consumed by other calculation methods in the service?
As D M mentions above, you should have your method return Observable<number>
.
Then, you can map
your input observable sources to your "price" value and do your getSharesOutstanding
work in a separate observable:
getPrice(ticker: string): Observable<number> {
return combineLatest([
this.getPrevDayClose(ticker),
this.getCurrDayLastPrice(ticker),
this.getWsLastPrice(ticker),
]).pipe(
map(([prevDayClose, currDayLastPrice, wsLastPrice]) => wsLastPrice ?? currDayLastPrice ?? prevDayClose)
);
}
getMarketCap(company: Company): Observable<number> {
return this.getPrice(company.ticker).pipe(
map(price => price * this.getSharesOutstanding(company))
);
}
Now, other places in your service can use this.getPrice()
and all of them will be updated when any of the source observables change.