4

I have a Subject (this.searchSubject) which I call next() on when I want to perform a search:

this.searchSubject.next(postBody)

This causes the following to fire:

this.searchSubject
      .switchMap((view: any) => {
         // upsert here records the search - needed
         return this.searchHistoryService.upsert(view)
          .flatMap(() => this.http.post(this.url, view))
          .map((data) => this.pageTransform(data));
      })
      .subscribe(res => {
        this.successSubject.next(this.pageTransform(res));
      }, err => {
        this.errorSub.next(err);
      });

Unfortunately, no matter what I do, I can't seem to keep the stream alive if this.errorSub.next(err); is called (the error condition).

Since the httpClient (this.http.post) returns a new observable each I wouldnt have thought handling the error would be an issue, but it seems this removes all observers from this.searchSubject.

Note I have a httpInterceptor which returns a thrown error for every error returned.

This must be an extremely common pattern, so what am I doing wrong?

Ben Taliadoros
  • 7,003
  • 15
  • 60
  • 97

1 Answers1

4

Your error handler is in the outer switchMap projection, thus it will close the outer stream in case of an error. You'll have to move it inside to your switchMap to keep the outer stream alive.

And since you're using rxjs@5.5.2 you can use the lettable operators which might make it easier to see where to put your error handlers.

this.searchSubject.pipe(
  switchMap((view: any) => {
   return this.searchHistoryService.upsert(view)
    .pipe(
      flatMap(() => this.http.post(this.url, view)),
      map((data) => this.pageTransform(data)),
      catchError(() => {
        this.errorSub.next(err); 
      })
    );
  })
).subscribe(() => {
  this.successSubject.next(this.pageTransform(res));
});

An important note if you switch to the lettable operators is that you have to import them from rxjs/operators like import { map, catchError } from 'rxjs/operators'; .

If you stay with the old syntax I think it will be as easy as to add a .catch after your .map() projection.

Daniel B
  • 8,770
  • 5
  • 43
  • 76
  • Thanks for this, I figured out that the outer observable was being closed as you said, its just a case now of trying to get my solution like yours, although i hadnt seen catchError, will that mean no error will be raised to searchSubject? – Ben Taliadoros Apr 11 '18 at 16:00
  • The `catchError` is just a rename of the old `catch` since the latter is a reserved keyword. Exactly, you'll have to handle the error inside. – Daniel B Apr 11 '18 at 16:11
  • You have to return something to catchError, so I return an Observable.of(err), which calls the success method in the subscription. Any idea how to avoid returning this? – Ben Taliadoros Apr 11 '18 at 16:41