1

I am trying to use concatMap to allow me to run requests in a sequential order without having to visually subscribe to every request that I am sending.

Everything is working fine, however when there is an error it carries on running through the pipe, which I do not want.

If it fails, I just want to be able to cancel all of the requests, stop it from running and display something. I have tried catchError however this doesn't seem to work / do what I want.

Take this example...

I want to reset a users password, upon password reset I want to POST to the /password/resets endpoint, I then want to automatically log the user in, so for that I then want to post to /auth/login and I then want to get the user GET - /user so I can use it throughout the application. If the request fails at any stage. I want to stop the pipes and throw a generic error which is shown at the bottom of the question.

this.userService.resetPassword(password)
.pipe(concatMap(() => this.authService.login(user.email, password)))
.pipe(concatMap(() => this.userService.me()))
.subscribe((user: User) => {
    this.userService.setUser(user);
});

Example:

this.userService.resetPassword(password)
.pipe(concatMap(() => this.authService.login(user.email, password)))
<-- IF IT FAILS ON THE ABOVE / ANY REQUEST I WANT TO STOP ALL REQUESTS AND SHOW NOTIFICATION -->
.pipe(concatMap(() => this.userService.me()))
.subscribe((user: User) => {
    this.userService.setUser(user);
});

The below snippet is something that I want to run on an error -

this.notificationService.notify('Unable to reset password, please try again.');

3 Answers3

0

can you add catchError to the same level of concatMap? (like:)

// also no need to put pipe for each piping. You can add a single one
this.userService.resetPassword(password)
  .pipe(concatMap(() => this.authService.login(user.email, password)),
        concatMap(() => this.userService.me()),
        catchError(err => throwError('error'))
  .subscribe((user: User) => {
    this.userService.setUser(user);
});

this catch error should get any error captured on the way, and throw it back. If I'm not mistaken. If you catch it inside the concatMap, you are resolving that innerObservable, but the outer keeps on going. So you need to stop the higher layer for it to behave as you want.

0

The way you use pipe and the rxjs operators are making it impossible to catch. The catchError operator can catch the exceptions throughout the pipe it is in.

Could you correct it and try once more?

yourCall().pipe(
    concatMap(() => otherCall()),
    concatMap(() => otherCall()),
    catchError( error => handleError())
).subscribe(result => doWhatYouWant());
talhature
  • 2,246
  • 1
  • 14
  • 28
-1

You can use catchError https://blog.angular-university.io/rxjs-error-handling/ Also, you can chain calls inside a single pipe() instead of repeating it.

Something along the lines of

this.userService.resetPassword(password)
.pipe(
    concatMap(() => this.authService.login(user.email, password).pipe(
        map(() => this.userService.me()),
        catchError(error => doSomething)))),
    ).subscribe((user: User) => {
    this.userService.setUser(user);
});
Tim
  • 3,910
  • 8
  • 45
  • 80
  • Thanks for the comment, if I use the `catchError` there though does it catch all errors? –  Jun 25 '19 at 13:46
  • Also, I implemented this and it doesn't catch the error unfortunately. I have console logged inside and also went to show a notification and it doesn't seem to be getting inside. –  Jun 25 '19 at 13:52
  • How does your request fail? Does it return a 401 or do you have your own error codes? I don't know your service implementation, maybe you can post your code – Tim Jun 25 '19 at 13:58
  • It returns a 401 from the request yeah –  Jun 25 '19 at 14:28
  • Did you find a solution? Could you post your service? – Tim Jun 26 '19 at 07:03