I have two methods in which I'm doing some asynchronous operation but I don't want method 2 to execute until or unless the response from method 1 is positive, to indicate that we can proceed further.
So, this is what I tried:
Method 1:
private method1(): Observable<any> {
return new Observable(() => {
executingSomething();
this.anotherSubscription.pipe(
map(x => {
console.log('Control is not reaching here');
Also, how to indicate the caller that method2 can be executed?
I can't return anything since I'm already returning the new Observable, above.
})
);
});
}
Caller:
concat(this.method1(), this.method2()).subscribe();
Issue: anotherSubscription
is not even getting executed and I can't think of any way to pass a response from within anotherSubscription
to the caller.
I feel that I'm not using the observables in correct sense, here but can't seem to find anything anywhere.
I've made some assumptions regarding your code prior to writing the solution. If the assumptions are wrong, then the answer may be as well.
executingSomething()
is a synchronous method with unrelated functionality, except that you want the whole thing to fail if it throws.anotherSubscription
is not a Subscribtion
but an Observable
(these are different things).Here's how I'd solve your problem:
class SomeClass {
private method1(): Observable<any> {
try {
executingSomething();
} catch (err) {
// This would return an errorred observable, which is great, since
// you can still subscribe to it (no need to change the return type
// of this method).
return throwError(err);
}
return this.anotherSubscription.pipe(
tap(() => {
console.log('Controls is reaching here!');
}),
);
}
private method2(): Observable<any> {
// This can be whatever obervable, using of(null) for demo purposes.
return of(null);
}
private parentMethod() {
this.method1()
.pipe(
switchMap(valueFromAnotherSubscription => {
// UPD1 - Implement your custom check here. This check will determine
// whether `method2` will be called.
if (valueFromAnotherSubscription === targetValue) {
return this.method2();
} else {
// UPD1 - If the check evaluates to `false`, reemit the same value
// using the `of` operator.
return of(valueFromAnotherSubscription);
}
}),
)
.subscribe(() => {
console.log('Done!');
});
}
}
The key operator here, as correctly indicated by Kevin, is switchMap
. Every time an observable (anotherSubscription
) emits, switchMap
will cancel it and subscribe to a different observable (whatever is returned from method2
).
This happens sequentially so method2
will only be subscribed to after method1
emits. If method1
throws, the whole pipeline will fail. You may also filter
the results of method1
to decide whether or not you want to switch to method2
.
Also, constructing observables using new Observable
is probably not needed in most cases. I have a rather large RxJS application and have never used this so far.
See code denoted with UPD1
comments.
Keep in mind that if an error is thrown by anotherSubscription
, the switchMap
function will not be called anyway.
Any specific reason you used
tap
instead ofmap
?Yes,
map
's purpose is returning a different value for every emitted value. Conversely,tap
is used for side-effects. I consider alog
statement to be a side-effect, sotap
is more appropriate. But you may do this inside amap
statement as well - it will work, just don't forget to return your value : ]One more thing. How do I filter my response from method1? In fact, how do I return something (such as a boolean to indicate whether to proceed further or not) when I'm returning
Observable<any>
? I tried returningof(false)
but I can't use thatfalse
until I subscribe to it and I'd need to do it inswitchMap(res => { if (res) { } )
, else it would execute method2.OK, so what's clear to me is that whenever
method1
emits the "correct" value, you want the subscriber to receive a value frommethod2
. What's not clear is what should happen whenmethod1
emits a "bad" value. I see two possible scenarios, tell me which one you need: A) whenmethod1
emits a "bad" value, you want to completely ignore such values, so the subscriber is not alerted at all; B) whenmethod1
emits a "bad" value, you simply want the subscriber to receive that value, whilst skippingmethod2
. I hope the difference is clear. I have updated the answer using option B.Ah, I was looking at some wrong console output and got confused. Thank you for your help. This works.