I want to call a server that can return an authorization failure (401) with the Angular2 HTTP class.
The request stream should look like this:
- The user makes a request to the server using myService.getSomething (). subscribe ()
- If the server returns 401: open a modal window that asks the user for its credentials.
- User will successfully log into the application
- Modal closes and calls back
- The callback should repeat the original request (myService.getSomething (). Subscribe ())
Here is what I have at the moment:
export class MyService {
doSomething () is used as follows: doSomething().map((r) => r.json()).subscribe((r) => ....)
Update 1
I modified my code to look like @Thierry Templier's solution.
private errorHandler(res: Response, ob: Observable<any>): Observable<Response> { if (res.status === 401) { let closedSubject = new Subject(); this.modalService.open(new ModalConfig({ content: LoginModalComponent, close: () => { closedSubject.next(res);} // I also tried .complete(), .next(null), .next(true), .next(false) })); return ob.retryWhen(() => closedSubject); } else { return Observable.throw(res.json()); } }
Unfortunately, this still does not work. RetryWhen runs immediately and does not wait for closedSubject.next () to be called. Therefore, it starts an infinite loop, dispatching the original Observable function (getSomething () function).
Update 2
I created a plunker to demonstrate an endless loop:
https://plnkr.co/edit/8SzmZlRHvi00OIdA7Bga
Warning: starting the plunker will spam your console using the string "test"
Update 3
Following Thierry's correct answer, I tried to find a way not to use the source field, since it is protected. After you asked about the rxjs tracker problem to make the field open, the participant answered with a better solution.
public get(url: string, options?: RequestOptionsArgs): Observable<Response> { return super.get(url, options).retryWhen((errors: any) => this.errorHandler(errors)); } private errorHandler(errors): any { return errors.switchMap((err) => { if (err.status === 401) { let closedSubject = new Subject(); this.modalService.open(new ModalConfig({ content: LoginModalComponent, close: () => { closedSubject.next(err); } })); return <any>closedSubject; } else { return Observable.throw(err.json()); } }); }
I do not use .catch, so I do not need to use the source field.
javascript angular typescript rxjs rxjs5
Jean-philippe leclerc
source share