I'm implementing an interface that has a function that returns Observable. I also need to pass some value to the Observable, but it may take some time to receive that value.
How can I still return the Observable and also make it wait for the needed value?
To be more specific, I'm implementing an HttpInterceptor and I want to set a token to the request header. The token value could be unavailable, so need to wait a little (asynchronously) and try again, until the value is received. Then set the token in the request header and continue.
How can I implement such mechanism?
@Injectable()
export class HttpXsrfInterceptor implements HttpInterceptor {
constructor(private tokenService: HttpXsrfTokenExtractor) { }
getToken(callback) {
let token = this.tokenService.getToken();
if (!token) {
// a valid token wasn't received. wait a little and try again
setTimeout(() => {
this.getToken(callback); //recursive call
}, 1000);
} else {
// found valid token
callback(token);
}
}
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
// this part should set req when a token is received, but it is asynchronous
this.getToken((token) => {
req = req.clone({headers: req.headers.set('X-XSRF-TOKEN', token)});
});
// this returns Observable. I must return Observable, but req is not ready at this point
return next.handle(req);
}
}
The easiest thing to do is use RxJs operators. Using switchMap
should be a good solution here. Essentially in this case, switchMap allows you to chain dependent observables together and only return the inner observable. It should look something like this:
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
return getToken.pipe(
switchMap(token => {
req = req.clone({headers: req.headers.set('X-XSRF-TOKEN', token)});
return next.handle(req);
}
);
}
Please note, You'll need to adjust your getToken to return an observable as well in order for this to work.