Reputation: 2618
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
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