I have the following TS function:
CheckRegUser(u: User): boolean {
let b: boolean = true;
let toSend = {
email: u.email
};
this.http.post("http://localhost:8080/", toSend).subscribe((data: Valid) => {
if(!data.validity){
b = false;
}
});
console.log(b);
return b;
}
Here I am connecting to an ExpressJS backend and I am getting back a boolean result. This part is working fine, but the problem is that the "return b" statement is executed before that the value of b is changed in "this.http", so b is always true no matter what the response from Express is.
I know that TS and JS are asynchronous and this problem is caused because of that, but I couldn't find the correct method to solve my issue. Any help would be appreciated.
Async methods can have the following return types: Task, for an async method that performs an operation but returns no value. Task<TResult>, for an async method that returns a value.
Asynchronous functions are prefixed with the async keyword; await suspends the execution until an asynchronous function return promise is fulfilled and unwraps the value from the Promise returned.
With that design, you call the asynchronous function, passing in your callback function. The function returns immediately and calls your callback when the operation is finished. With a promise-based API, the asynchronous function starts the operation and returns a Promise object.
You can try with async await
async CheckRegUser(u: User): Promise<boolean> {
let toSend = {
email: u.email
};
let k = await this.http.post("http://localhost:8080/", toSend).subscribe((data: Valid){
let b: boolean = true;
if(!data.validity){
b = false;
}
return b
});
console.log(k);
return k;
}
I had this common problem when I was just starting to learn Observables/Reactive programming with a Google Maps app as well :D!
Spot on, you realised that asynchronous function hasn't mutated the b
boolean flag yet when the function synchronously returns b
(that defaulted to true
);
To fix this it might be easier to restructure your function to return the Observable
to the caller.
and maybe look up Observable
chaining or similar concept Promise
chaining.
Old example:
CheckRegUser(u: User): boolean {
const b: boolean = true;
const toSend = {
email: u.email
};
const httpPost: Observable<aJsonObject> = this.http.post("http://localhost:8080/", toSend)
const httpPostSubscription: Subscription = httpPost
.subscribe((data: Valid) => { // This is asynchronous
if (!data.validity) {
b = false;
}
});
console.log(b);
return b; // This is effectively sync returning your default value `b = true`;
}
It would be better if you could rename your variables to be clearer.
b
or isDataValid
.
Might also be good practice to start functional-style with const
variables to help avoid mutability issues.
If you're more familiar with Promises
, you could also try to promisify
the httpClient.post Observable.
General gist of it is to pass the Observable
back to the caller and .subscribe
it there.
When something is returning asynchronously, you should return the asynchronicity all the way back to the top.
Refactor code to reflect these practices
CheckRegUser(user: User, httpClient: HttpClient): Observable<Valid> {
// 1. Data to send
type EmailPost = { email: string }
const emailJsonToSend: EmailPost = { // I prefer explicit typing wherever possible :tada: :D
email: user.email
};
// 2. POST the data to the web server
const emailHttpPostObs: Observable<Valid> = httpClient.post("http://localhost:8080/", emailJsonToSend);
return emailHttpPostObs;
}
CallerSubmitUserFunction(user: User, httpClient: HttpClient) {
// Made some assumptions, please comment and we can work out a better solution
// Explicitly typed things as an example.
// 1. You have a user e.g. new User(name:'myUser', email: '[email protected]');
const userToSend: User = user;
// 2. You POST the user.email and get response.
const validatedUserDataObs: Observable<Valid> = CheckRegUser(userToSend, httpClient);
// 3. You check whether the server accepted the data and whether it was valid.
const validatedUserDataObs: Subscription = validatedUserDataObs
.subscribe((data: Valid) => {
// Perform data validation or Error checking here.
// If data is valid,
if (dataValidationFunction()) {
// Do something here
// Instead of trying to return the boolean in the asynchronouse function.
// Directly do something after the server responds (whenever it happens).
}
}) // catch Error
// It would also be better if you could rename your variables to be more self-indicative
// var dataIsValid
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With