1

I'm in an Angular route resolver and want to return an observable.

I need to subscribe to multiple async processes in order:

A => B(a) => C(b)

C depends on B and B depends on A. A must complete, then B, then C, but I only want the value from C to be used to cause the route to resolve.

I've tried two different approaches:

return A.pipe(
  concatMap(a => 
    B(a).pipe(
      concatMap(b => 
        C(b).pipe((c) => c); // also tried of(c)
      )
    )
  )
);

I've also tried

return A.pipe(
  concatMap(a => {
    return B(a).pipe(map(b => {a: a, b: b});
  ),
  concatMap({a, b} => {
    return C(b);
  )
);

How do I subscribe to A, then B, then C ..., and then only get the value from the innermost observable?

If I put a tap after my last concatMap I get my expected return value. But my resolver never resolves? (or the wrong thing is getting emitted? I cannot really tell.)

jkyoutsey
  • 1,969
  • 2
  • 20
  • 31

2 Answers2

2

If one of the observables in the chain never completes (like route params or query params), it'll halt the whole train.

switchMap should do:

A.pipe(
    switchMap(B), // which is more or less the same as `switchMap(a => B(a))`
    switchMap(C),
).subscribe(//...
mbojko
  • 13,503
  • 1
  • 16
  • 26
  • B needs the value from A and C needs the value from B. Won't switchMap stop the outer when the inner emits? – jkyoutsey Oct 18 '19 at 22:07
  • B gets A's output and C gets B's output. You can try whether it works, or write some more detail about the streams involved. – mbojko Oct 18 '19 at 22:17
  • I did not try your answer because I got an answer from another source that said to simply use a take(1) which did exactly what I needed. Somewhere, and your answer is correct in this at the very least, one of my observables was not completing. – jkyoutsey Oct 18 '19 at 23:40
2

Route resolvers need to complete before the Angular Router will continue. This is the same for route guards also. Adding a operator that takes an emission, such as take(1), or first() and completes will solve the problem.

return A.pipe(
  concatMap(a => {
    return B(a).pipe(map(b => {a: a, b: b});
  ),
  concatMap({a, b} => {
    return C(b);
  ),
  take(1)
);
Brandon
  • 706
  • 6
  • 4
  • It works, but why is it that when it is a single observable I don't have to use any operators like take? – eddy Jan 25 '21 at 20:09