Search code examples
angularrxjsngrx

RxJS filter an observable with value in another Observable


I am looking for the best RxJs way of filtering an Observable with the value held in another.

Firstly I have an observable containing a ticker which comes from the route Params. Lets say it is "BTC" in ticker$

Then I have a store observable which returns me a list of coins (1414 of them) in fullCoinList$

I want the this.coin$ observable to contain only the items in this.fullCoinList$ observable that contains the string "BTC" somewhere in the ticker name.

FullCoinList$ looks like this.

  [{ticker: "ETHBTC", price: "0.04597600"}
   {ticker: "LTCBTC", price: "0.00457100"}
   {ticker: "BNBBTC", price: "0.01008450"}
   {ticker: "NEOBTC", price: "0.00163300"}
   {ticker: "QTUMETH", price: "0.00541200"}
   {ticker: "EOSETH", price: "0.00229400
   .... + 1408more]

My NgOnInit looks like this

ngOnInit(): void {
    this.activatedRoute.paramMap.subscribe( (params: ParamMap) => {
      this.ticker$ = of(params.get('ticker'))
    })

    this.fullCoinList$ = this.store.pipe(select(selectAllCoins))
    
    this.coins$ = this.fullCoinList$.pipe(
      filter( coin => coin.ticker.includes(this.ticker$)) // this line needs work
    )
  }

Is this a good use case for mergeMap, concatMap or something similar? And how would I best implement it? I'm not sure includes is the correct method either.

EDIT: I have added a stackBlitz Blitz


Solution

  • I would use combineLatest to combine both observables and go from there.

    import { combineLatest } from 'rxjs';
    import { map } from 'rxjs/operators';
    ...
    ngOnInit(): void {
        // we can get rid of a subscription here and assign it to the observable directly
        this.ticker$ = this.activatedRoute.paramMap.pipe(
          map(paramMap => paramMap.get('ticker')),
        );
    
        this.fullCoinList$ = this.store.pipe(select(selectAllCoins))
        
        this.coins$ = combineLatest(this.fullCoinList$, this.ticker$).pipe(
          // the filter is the array filter and not rxjs filter
          map(([fullCoinList, ticker]) => fullCoinList.filter(fullCoin => fullCoin.ticker.includes(ticker))),
        );
      }
    

    Something like that should work.