user66875
user66875

Reputation: 2618

Nested observables / subscribe within observable

Having read that you should never subscribe within another observable, I am having major difficulties understanding how to properly handle nested observables.

For every Candidate emitted, I want to match against multiple regular expressions, provided as an observable getPatterns$(). If one is found, it will be attached to the Candidate object.

 class Candidate {
    public name: string;
    public matchingRegularExpression: RegExp;
 }

 listOfCandidates = [new Candidate('one'), new Candidate('two')];

 private matchCandidates$(textToMatch: string): Observable<Candidate> {
    return from(this.listOfCandidates)
      .pipe(
        map(f => { 
          f.regExp = this.getRegExp(f); // sequential
          return f;
        }),
        map(cand: Candidate => {
           this.getPatterns$().subscribe(patterns => {
             if (....do some regexp matching...){
                cand.matchingRegularExpression = pattern;
             }
           });
        })
      )

I tried using mergeMap or switchMap, but those seem to be used when you want to merge 1 outer object with n inner ones. But my inner observable should simply extend my Candidate object and emit 2 values in this example.

Upvotes: 0

Views: 177

Answers (1)

Dams
Dams

Reputation: 61

So first, it's considered as a bad practice because you completely lose the reference of your second subscription, which could result in a leak if the source continue emitting.

Fortunately we have an operator called switchMap, it allows us to switch on a new observable, and thus, avoid subscribing inside the observer function.

The main difference between switchMap and other flattening operators is the cancelling effect. On each emission the previous inner observable (the result of the function you supplied) is cancelled and the new observable is subscribed. You can remember this by the phrase switch to a new observable.

edit: add snippet

class Candidate {
    public name: string;
    public matchingRegularExpression: RegExp;
 }

 listOfCandidates = [new Candidate('one'), new Candidate('two')];

private matchCandidates$(textToMatch: string): Observable<Candidate> {
    return from(this.listOfCandidates)
      .pipe(
        map(f => { 
          f.regExp = this.getRegExp(f); // sequential
          return f;
        }),
        switchMap(cand: Candidate => {
          return this.getPatterns$().pipe(
            map(patterns => {
              if (....do some regexp matching...){
                cand.matchingRegularExpression = pattern;
              }
              return cand
            })
          )})
         )

Upvotes: 2

Related Questions