Reputation: 553
I've been trying to learn Angular (Typescript) + ASP Net Core and I dont understand how should I wait for an observable to complete. Basically, i've created a login service on the backend, which works. However, i've tried to create a simple helper to handle http responses easier on the client side. The issue is that it runs two times: on the first one it thinks RequestResponse is undefined (because it skips the http request) while on the second the RequestResponse is populated and it works as expected.
Here's the Http helper:
get<T>(url: string): Observable<T> {
let options = this.doHeaders();
return this.doSub(this.http.get(this.doUrl(url), options));
}
private doSub<T>(obs: Observable<Response>) {
var ob1: Observable<T> = obs.map(this.extractData)
.catch(this.handleError);
return ob1;
}
Here's the RequestResponse:
export class RequestResponse {
public error: string;
public isOk: boolean;
public code : StatusCode;
}
Here's the Service:
@(Injectable)
export class RequestService {
constructor(
private net: NetworkService,
private loaderService: LoaderService,
private storage: StorageService,
) {
}
login(email: string, password: string, rememberMe: boolean = false): RequestResponse {
var r = new RequestResponse();
// I need to make this wait
this.net.get<LoginModel>(`Authentication/Login/${email}/${password}`).subscribe(t => {
this.storage.token = t.token;
this.storage.email = rememberMe ? email : null;
this.storage.password = rememberMe ? password : null;
this.storage.user = t.user;
r.isOk = true;
r.code = StatusCode.OK;
},
error => {
r.isOk = false;
switch (error.message) {
case '403':
r.code = StatusCode.Forbidden; r.error = 'You've been suspended'; return;
case '404':
r.code = StatusCode.NotFound; r.error = 'User not found'; return;
case '406':
r.code = StatusCode.NotAcceptable; r.error = 'Invalid Email/Password'; return;
default:
r.code = StatusCode.InternalServerError; r.error = 'Internal Error'; return;
}
});
// First time it is skipping all the way down, returning null
return r;
}
}
Here's how i'm trying to use it:
login() {
this.loginResponse = this.requestService.login(this.email, this.password, this.rememberMe);
console.log(this.loginResponse);
if (!this.loginResponse.isOk) {
this.toasterService.pop('error', 'Error', this.loginResponse.error);
return;
}
this.router.navigateByUrl('/home');
}
I've read about Promises and Observables and I've tried many changes, but the first RequestResponse being null was still a problem.
How should I deal with this?
Upvotes: 1
Views: 3105
Reputation: 60518
It is recommended that you use the subscribe in the component, not in the service. That way you will have a better mechanism to react when the subscription is complete, plus provide ways to cancel or unsubscribe.
Code from my service
getProducts(): Observable<IProduct[]> {
return this.http.get<IProduct[]>(this.productsUrl)
.pipe(
tap(data => console.log(JSON.stringify(data))),
catchError(this.handleError)
);
}
Code from my component
ngOnInit(): void {
this.productService.getProducts().subscribe(
(products: IProduct[]) => {
this.products = products;
// Any code to be run after the subscription is complete goes here
},
(error: any) => this.errorMessage = <any>error
);
}
For a "complete" sample application, check out my github repo: https://github.com/DeborahK/Angular-GettingStarted
Upvotes: 3