2
votes

I want to have a condition inside flatMap that checks what was returned by first observable. If condition is not met I would like to break and navigate to different page.

this.service.getData(id)
  .flatMap((data) => {
    if (!data) {
      return Observable.throw(new NoDataFoundError());
    }
    return Observable.forkJoin(
      this.service.getData2(id2),
      this.service.getData3(id3),
    );
  })
  .subscribe(
    ([data2, data3]) => {
      this.data2= data2;
      this.data3= data3;
    },
    (err) => {
      if (err instanceof NoDataFoundError) {
        this.router.navigate(...);
      }
    }
  );   

Currently I'm throwing specific error and catching it however I don't like this solution as it's not the only piece of code that could throw an error and the if is not scaling.

I thought about filter or takeWhile operators but I won't be able to execute the redirect.

I also thought about returning Observable.of instead of throwing (in line 4) but then I would have to do the if in subscribe which also smells.

1
The code looks pretty good as-is. Could you please elaborate on your concerns? There's a few different patterns that you could use, but it depends on what else is going on.Richard Matsen

1 Answers

9
votes

You can execute this.router.navigate and return Observable.empty() inside .flatMap. This way you will have a single if statement.

.flatMap(data => {
  if (!data) {
    this.router.navigate(...);
    return Observable.empty();
  }
  return (...);
})

But usually Observables should be lazy and pure(free of side effects) this will make them predictable and easy to compose. Side effects should be performed only by subscriber.

In your specific case, it seems like the proper solution would be to put this logic in the route guard, like described here - https://stackoverflow.com/a/39162538/3772379