Yes, there is a better way!
RxJS provides many different operators and static functions for combining, filtering, and transforming observables. When you use what the library provides, you do not need to have nested subscriptions.
In general, I find it simpler to not do any logic at all inside the subscribe, but rather design observables that emit the exact data that is needed.
A simplistic example could look like this:
someValue$ = source1$.pipe(
switchMap(val1 => useCond1 ? source2$ : of(val1))
);
someValue$.subscribe();
switchMap
will subscribe to an "inner observable" whenever it receives an emission. The logic above says to either return the value emitted from source1$
(val1
) or return whatever source2$
emits depending on the value of useCond1
.
So source2$
will only get subscribed to when useCond1
is true;
Note: the function inside switchMap
should return an observable (because switchMap subscribes to it), so of
was used to turn the emitted value into an observable.
In your case, let's assume you want to emit some calculated value, based possibly on the other two sources.
We can use combineLatest
to create a single observable based on 3 different sources. Since you only want to optionally call source2$
and source3$
, we can define the sources based on your conditions. We can then use map
to transform the array of values from the 3 sources, into the desired output:
someValue$ = source1$.pipe(
switchMap(val1 => {
const s1$ = of(val1);
const s2$ = useCond1 ? source2$ : of('default val2');
const s3$ = useCond2 ? source3$ : of('default val3');
return combineLatest([s1$, s2$, s3$]);
}),
map(([val1, val2, val3]) => {
return ... // your logic to return desired value
})
);
combineLatest
will emit an array containing the latest emissions from each source whenever any source emits. This means someValue$
will emit the latest calculated value whenever any of the sources change.