Reputation: 954
I have a problem. In my angular project I am trying to do a Http POST call, to login in my website. I provide the call with an username and password. If the API endpoint returns null, the login failed and if the endpoint returns an Account object it succeeded. The code to make the Http POST call is the following:
import { Injectable } from '@angular/core';
import {Account} from "../models/Account";
import {Observable} from "rxjs";
import {HttpClient, HttpHeaders} from "@angular/common/http";
import {PostService} from "./post.service";
@Injectable({
providedIn: 'root'
})
export class AccountService {
public loggedInAccount: Account | null;
private httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'application/json',
//Authorization: 'my-auth-token'
})
};
constructor(private httpClient: HttpClient) {
this.loggedInAccount = null;
}
public login(account: Account):Account | null {
this.restLogin(account).subscribe(
(data) => {
if (data != null) {
this.loggedInAccount = data;
}
return data;
},
(error) => {
alert('Error: Status ' + error.status + ' - ' + error.error);
});
return null;
}
private restLogin(account: Account): Observable<Account> {
let email = account.email;
let password = account.password;
return this.httpClient.post<Account>('http://localhost:8080/account/login', {email, password}, this.httpOptions);
}
}
The problem is that the login()
function always returns null. I understood I had to use some kind of async/await, but I can't seem to figure out how to use it in my case. Here is what I tried. In the AccountService:
public async login(account: Account):Promise<Account | null> {
let returnValue = null;
await this.restLogin(account).subscribe(
(data) => {
if (data != null) {
this.loggedInAccount = data;
}
returnValue = data;
},
(error) => {
alert('Error: Status ' + error.status + ' - ' + error.error);
});
return returnValue;
}
On the login page:
public onLoginClick(): void {
let email = (document.getElementById("txtEmail") as HTMLInputElement).value;
let password = (document.getElementById("txtPassword") as HTMLInputElement).value;
if (this.accountService.login(new Account(email, password)) != null) {
this.accountService.loggedInAccount!.posts = this.postService.getAccountPosts(this.accountService.loggedInAccount!.id);
this.route.navigate(['/']);
}
else {
(document.getElementById("txtMessage") as HTMLDivElement).innerHTML = "Incorrect email/password!"
}
}
But this gives me an error on the login page on this line:
this.accountService.loggedInAccount!.posts = this.postService.getAccountPosts(this.accountService.loggedInAccount!.id);
saying that this.accountService.loggedInAccount
is null, but that couldn't be possible, because I set it with this in de AccountService:
if (data != null) {
this.loggedInAccount = data;
}
return data;
Can someone tell me how to fix and optimize (if possible) this?
Upvotes: 0
Views: 1695
Reputation: 2397
The problem is that the login() function always returns null
Yes, there is a problem with how you return data from the login
method. You use subscribe
which is executed in async but does not return any value. You should use something like map
. See this post with more details : Return a Observable from a Subscription with RxJS
So your login
function should work if you try something like this (not tested) :
public login(account: Account): Observable<Account | null> {
return this.restLogin(account)
.pipe(
map(result => {
// TODO: do something with "result" ?
// If not, you can remove the "map" pipe and only keep "catchError"
return result;
}),
catchError(error => {
// TODO: handle error
return of(null);
})
);
}
Then you can call your login
method like this :
this.accountService.login(new Account(email, password)).subscribe(account => {
if (account !== null) {
// Login succeeded, redirect
} else {
// Login failed
}
})
Upvotes: 2