Angular 5 nested returns - javascript

i am trying to create a function that should return a boolean after calling my API
so i created the following function:
verify() {
console.log('lol');
let user = JSON.parse(localStorage.getItem('currentUser')) as User;
return this.http.get(environment.apiUrl + 'Users/' + user.id,
{params: ApiHelperService.prototype.createParams([], true)}).subscribe(
result => {
return true;
},
error => {
return false;
}
);
}
And then i called it:
if (this._userService.verify()) {
return true;
}
else {
this._router.navigate(['/login'], {queryParams: {returnUrl: state.url}});
return false;
}
However, sadly the function returns before the response from the server.
So my question is how can I create these nested return statements to make sure it returns the correct value?

suggest you make use of async/await way like as below
async verify() {
console.log('lol');
let user = JSON.parse(localStorage.getItem('currentUser')) as User;
return await this.http.get(environment.apiUrl + 'Users/' + user.id,
{params: ApiHelperService.prototype.createParams([], true)})
).toPromise();
}
use it like this
async verifyoutput()
{
try
{
const verify = await verify();
return true;
}
catch (e)
{
return false;
}
}

verify():Observable<any> {
console.log('lol');
let user = JSON.parse(localStorage.getItem('currentUser')) as User;
return this.http.get(environment.apiUrl + 'Users/' + user.id,
{params: ApiHelperService.prototype.createParams([], true)})
}
...
verify().subscribe(result => {
return true
},err => {
this._router.navigate(['/login'], {queryParams: {returnUrl: state.url}});
return false;
})

Related

Alternative to complex else if ladders

I have a function that returns a value called user_id. But there are many conditions to be checked.
condition 1: check service variable
condition 2: If no, get user_id from localstorage
condition 3: If no, get firebase_uid from localstorage, and call function findUserId(firebase_uid) which will return user_id
condition 4: if no, get uid from firebase and call findUserId(uid)
here is the code.
export class UserService {
user_id : any;
firebase_uid: any;
id: any;
returnUser_id() {
if(this.user_id) {
return this.user_id
}
else {
this.storageService.get('user_id').then(val =>{
if(val) {
this.user_id =val
return this.user_id
}
else {
this.storageService.get('firebase_uid').then(value =>{
if(value) {
this.firebase_uid = value
this.findUserId(this.firebase_uid).subscribe(q =>{
console.log(q)
this.id = q;
for(let i =0; i<this.id.length;i++) {
this.user_id = this.id[i].id
return this.user_id
}
this.storageService.set('user_id', this.user_id ).then(result => {
console.log('Data is saved');
}).catch(e => {
console.log("error: " + e);
});
})
}
else {
this.afauth.authState.subscribe(user =>{
if(user) {
this.firebase_uid = user.uid;
this.storageService.set('firebase_uid', this.firebase_uid ).then(result => {
console.log('Data is saved');
}).catch(e => {
console.log("error: " + e);
});
this.findUserId(this.firebase_uid).subscribe(data =>{
this.id = data;
for(let i = 0 ;i<this.id.length; i++ ){
this.user_id = this.id[i].id
return this.user_id
}
this.storageService.set('user_id', this.user_id ).then(result => {
console.log('Data is saved');
}).catch(e => {
console.log("error: " + e);
});
})
}
})
}
}).catch(err =>{
console.log(err)
})
}
}).catch(err =>{
console.log(err)
})
}
}
}
findUserId function
findUserId(uid): Observable<any> {
return this.http.get<User[]>(this.user_url + 'users?filter[fields][id]=true&filter[where][firebase_uid]=' +uid )
}
This code is so complex and difficult to understand. Is there any alternative to traditional if else statements.
Thank you in advance
There are some repeatable code, so we can move repeatable code into method and reuse it. Moreover we can simplify our code using async keywords.
if(this.user_id)
return this.user_id;
else {
let user_id = await this.storageService.get('user_id');
if (user_id)
return user_id;
else {
let firebase_uid = await this.storageService.get('firebase_uid');
if (firebase_uid) {
await reusableFindUserId(firebase_uid);
if (this.user_id)
await setStorageService();
}
else {
let user = await this.afauth.authState();
if (user) {
this.firebase_uid = user.uid;
await reusableFindUserId(firebase_uid);
if (this.user_id)
await setStorageService();
}
})
}
}
}
and reusable methods:
async reusableFindUserId(firebase_uid){
this.id = await this.findUserId(firebase_uid);
for(let i =0; i<this.id.length;i++) {
this.user_id = this.id[i].id;
return this.user_id;
}
}
async setStorageService() {
return await this.storageService.set('user_id', this.user_id );
}
You can get rid of this else, because you return in the if-block above. If you don't return, the remaining code will be executed.
You can go through the hole function and check if the elses are necessary. If you return, you don't need an else :)
Another point is, you can extract some parts of the code into dedicated functions. Your main function will be much cleaner and shorter.
if(val) {
this.user_id =val
return this.user_id
}
// No need for the else...
else {
....
}

how to let a function wait for result returned by another function?

i have a function called 'updateProfile()' which has a condition which is if(emailChangeConfirm), this condition depends upon the value of variable 'emailChangeConfirm' , this variable gets the value returned by another function called 'updateEmailAllProcessing()'
the condition 'if(emailChangeConfirm)' is not getting satisfied at all because compiler is not waiting for the function 'updateEmailAllProcessing()' to return the value for variable 'emailChangeConfirm'.
I used async/await for this but that is also not working as i want
Desired Solution :
function 'updateProfile()' must wait for the function 'updateEmailAllProcessing()' to get the result in 'emailChangeConfirm' so that i can enter in the condition 'if(emailChangeConfirm)'.
I am using typescript and working on hybrid app with ionic 3 and angular 5.
async updateProfile(updatedData : Credentials,tarUser : Credentials)
{
// console.log(tarUser,'<<--->>>',updatedData)
let count : number = undefined;
let emailChangeConfirm : boolean;
if(updatedData.name)
{
if(tarUser.name != updatedData.name)
tarUser.name = updatedData.name;
else
count++;
}
if(updatedData.email)
{
if(tarUser.email != updatedData.email)
{
**emailChangeConfirm = await this.updateEmailAllProcessing();**
console.log(emailChangeConfirm)
**if(emailChangeConfirm)
tarUser.email = updatedData.email;**
}
else
count++;
}
if(updatedData.phoneNo)
{
if(tarUser.phoneNo != updatedData.phoneNo)
tarUser.phoneNo = updatedData.phoneNo;
else
count++;
}
if(updatedData.photoURL)
{
if(tarUser.photoURL != updatedData.photoURL)
tarUser.photoURL = updatedData.photoURL;
else
count++;
}
if(count)
this.mesService.presentToast('Nothing Updated!!')
else **if(emailChangeConfirm)**
{
this.dbServe.editUser(tarUser).then(() =>
{
console.log("User Edited Successfully with email change too");
this.authServ.updateEmail(tarUser.email).then(() =>
{
console.log('login email updated');
this.authServ.logout();
})
//this.close();
})
}
else
{
this.dbServe.editUser(tarUser).then(() =>
{
console.log("User Edited Successfully with No email change");
this.close();
})
}
}
**async updateEmailAllProcessing()**
{
let result : boolean;
let alert = this.mesService.emailChangeConfirmation();
alert.present();
alert.onDidDismiss((data) => {
console.log('data->',data);
if(data)
{
let alert1 = this.mesService.passwordPrompt();
alert1.present();
alert1.onDidDismiss(data1 =>
{
console.log('password->',data1);
if(data1)
{
this.authServ.reauthenticateUser(data1).then(() =>
{
console.log('User Reauth Done');
result = true;
})
}
else
result = false;
})
}
else
result = false;
})
**return result;**
}
You need updateEmailAllProcessing to return a promise so you can await on it. and resolve the promise with the result inside the callback.
async updateEmailAllProcessing()
{
return new Promise((resolve, reject) => {
let result: boolean;
let alert = this.mesService.emailChangeConfirmation();
alert.present();
alert.onDidDismiss((data) => {
console.log('data->', data);
if (data) {
let alert1 = this.mesService.passwordPrompt();
alert1.present();
alert1.onDidDismiss(data1 => {
console.log('password->', data1);
if (data1) {
this.authServ.reauthenticateUser(data1).then(() => {
console.log('User Reauth Done');
resolve(true);
})
}
else
resolve(false);
})
}
else
resolve(false);
})
});
}

My arr is empty when I return it with a function

I'm trying to pass arrEntree in my return, however it's inside a promise. How would I fix this issue? The function query iniaites a new promise but like everytime ArrEntree is printed empty, because it gets called before the promise is finished processing. How would I finish the promise then only call my return...? How would I solve this issue.
function query(statement, params, first) {
return new Promise(function(resolve, reject) {
connection.query(statement, (params || []), function(err, rows) {
if (err) {
console.log("err", err);
if (err.code === "ETIMEDOUT") {
connectToDb();
return query(statement, params, first);
}
reject(err);
} else {
if (first) {
resolve(rows[0]);
} else {
resolve(rows);
}
}
});
});
}
function sendPlanEmails(){
if (plans.length === 0) {
return true;
}
const orders = plans.map(plan=>{
const arrEntree = []
const planData = srcData.plans[plan.productId];
const entrees = plan.entrees;
const entreeID = Object.keys(plan.entrees);
query('select * from entrees where entree_id in (' + entreeID.join(',') + ')')
.then(function(results){
results.forEach(function(element){
entreeID.forEach(function(second_elem){
if(element.entree_id==second_elem){
console.log('worked until here')
const quantity = plan.entrees[second_elem];
const name = element.entree;
arrEntree.push({name:name, quantity:quantity});
}
})
})
})
return {
days:plan.days.days,
planDataTitle:planData.title,
breakfast:plan.meals[0],
lunch:plan.meals[1],
dinner:plan.meals[2],
entreeArry:arrEntree
};
});
const template_mp = srcData.orderPage.mailchimp_template_mp || 'order_confirmation';
return utils.sendMealPlanEmail(template_mp, {
from: from,
order: orders,
});
}

How to ensure the chain of promises return an object

I have this function that has a chain of promises and I want to return an object:
var signIn = function(fb_ID,fb_accessToken) {
console.log("signin!")
var promise = new Parse.Promise();
var TokenStorage = Parse.Object.extend("tokenStorage");
var query = new Parse.Query(TokenStorage);
query.equalTo('facebookID', fb_ID);
query.ascending('createdAt');
var password;
var username;
var output = {};
var user;
// Check if this ID has previously logged in, using the master key
return query.first({ useMasterKey: true }).then(function(tokenData) {
// Update the accessToken if it is different.
if (fb_accessToken !== tokenData.get('fb_accessToken')) {
console.log('1')
user = tokenData.get('user');
user.fetch({
success: function(data) {
username = data.get('username')
tokenData.set('fb_accessToken', fb_accessToken);
/*
password = new Buffer(24);
_.times(24, function(i) {
password.set(i, _.random(0, 255));
password = password.toString('base64')
})
*/
password = (Date.now().toString(36) + Math.random().toString(36).substr(2, 10)).toUpperCase();
user.setPassword(password);
tokenData.set('password',password)
console.log('fetch')
return
}
}).then(function(){
tokenData.save(null, { useMasterKey: true }).then(function(tokenuser) {
console.log('tokensave')
user.save();
return Parse.User.logIn(username, password);
}).then(function(data) {
// Return the user object.
console.log('output return')
output.success = true
output.isnewuser = false
output.username = username;
output.password = password;
output.fb_accessToken = fb_accessToken;
//return Parse.Promise.as(output);
//promise.resolve(output)
//return promise
return output
});
})
} else {
console.log('2')
Parse.Promise.as().then(function() {
username = tokenData.get('username');
password = tokenData.get('password');
return
}).then(function(){
return Parse.User.logIn(username, password)
.then(function(data) {
// Return the user object
output.success = true
output.isnewuser = false
output.username = username;
output.password = password;
output.fb_accessToken = fb_accessToken;
console.log('oo'+JSON.stringify(output))
//return Parse.Promise.as(output);
//promise.resolve(output)
return output
});
})
}
})
//return promise
}
The function has two if statements and I would like that both will return 'output' object when I call:
signIn(fb_ID,fb_accessToken).then(function(data){
if (data.success == true) {
console.log('inn'+JSON.stringify(data))
response.success(data)
}
else {
console.log('errr')
response.error(data)
}
})
The 'data' object should be the 'output' object inside the SignIn function. Any idea?
You should put return before user.fetch and tokenData.save in first if block. In the else block put return before Parse.promise.as.
Your current implementation looks like something similar to this.
var someFunction = function () {
return mainPromise().then(function () {
if (someCondition) {
somePromiseOne().then(function () {
return data;
});
}
else {
somePromiseTwo().then(function () {
return data;
});
}
});
};
In the both cases you should put return before somePromiseOne and somePromiseTwo in order to pass the data to the promise chain.
You can do quite a lot to tidy things up ... and get it working.
First, you can (and should) move the code from the user.fetch({ success:... }) callback into the following then's callback. "Property-style" callbacks should be avoided when a promise interface is available (and already used).
Then, you might aim for flow control as follows :
doSomethingAsync().then(function() {
var promise;
if(condition) {
promise = ...; // deliver username and password
} else {
promise = ...; // deliver username and password
}
return promise.then(function(details) {
return login().then(function() {
// fully compose output object here
return details;
});
});
});
In practice, the code will be more extensive due to the number of async steps and the volume of synchronous code, particularly in the first condition.
In full, you might end up with something like this :
var signIn = function(fb_ID, fb_accessToken) {
var query = new Parse.Query(Parse.Object.extend('tokenStorage'));
query.equalTo('facebookID', fb_ID);
query.ascending('createdAt');
// Check if this ID has previously logged in, using the master key
return query.first({ useMasterKey: true }).then(function(tokenData) {
var promise;
// Update the accessToken if it is different.
if (fb_accessToken !== tokenData.get('fb_accessToken')) {
var user = tokenData.get('user');
promise = user.fetch().then(function(data) {
var details = {
username: data.get('username'),
password: (Date.now().toString(36) + Math.random().toString(36).substr(2, 10)).toUpperCase()
};
tokenData.set('fb_accessToken', fb_accessToken);
tokenData.set('password', details.password);
user.setPassword(details.password);
// Assuming here that `tokenData.save()` and `user.save()` are both async and can be executed in parallel.
return Parse.Promise.when([
tokenData.save(null, { useMasterKey: true }),
user.save()
]).then(function() {
return details;
});
});
} else {
// here `promise` mimics the final successful state of the promise in the other condition.
// ie. promise-wrapped details
promise = Parse.Promise.as({
username: tokenData.get('username'),
password: tokenData.get('password')
});
}
return promise.then(function(details) {
// whichever condition was executed, username and password details are delivered here in an identical format.
return Parse.User.logIn(details.username, details.password).then(function() {
details.success = true;
details.isnewuser = false;
details.fb_accessToken = fb_accessToken;
return details; // deliver details to signIn's caller
});
});
});
}

How promise works with nested function calls

I have a piece of code which deals with user's data. There are bunch of nested function calls :
f1(){
f2(){
....
fn{
///
}
}
}
fn accesses a database which means it's asynchronous, so I wrote it somehow that it returns a promise and in fn-1 (the function which calls fn) , we use .then() to wait for this promise. But it looks like now I have to return a promise in fn-1 and so on. Is that true ?
var keyValueExists = function(key, value) {
var query = {};
query[key] = value;
return new Promise(function(resolve, reject) {
User.count(query, function(err, count) {
if (err) {
console.log(err);
console.log('Problem with `.find` function');
reject('Problem with `.find` function');
} else {
resolve(count !== 0);
}
});
});
};
var addUser = function(newUserInfo) {
var validationResult = Common._validateUserInfo(newUserInfo);
if (validationResult.isOK) {
keyValueExists('userName', newUserInfo.userName).then(function(userNameAlreadyExists) {
if (userNameAlreadyExists) {
validationResult = {
isOK: false,
reason: 'Username already exists',
infoWithBadInput: 'userName'
}
} else {
var newUserId = generateUserId();
//TODO: change it somehting more flexible. e.g. a predefined list of attributes to iterate over
var newUser = {
'userName': newUserInfo.userName,
'password': newUserInfo.password,
'userId': newUserId,
'lastModificationTime': Common.getCurrentFormanttedTime(),
'createdTime': Common.getCurrentFormanttedTime()
};
var user = new User(newUser);
user.save(function(err) {
if (err) {
console.log(err);
console.log('There is a problem saving the user info');
} else {
console.log('A new user added: ');
console.log(newUser);
}
});
}
return validationResult;
});
} else {
return validationResult;
}
};
addUser returns undefined ! It looks like that the caller of addUser doesn't wait for it !
This is what you are effectively doing in your addUser function
var addUser = function(newUserInfo) {
var validationResult = Common._validateUserInfo(newUserInfo);
if (validationResult.isOK) {
// ... do something asynchronously without returning anything
} else {
return validationResult;
}
}
So, yeah, if validationResult.isOK, adduser WILL return undefined
Here's some code loosely based on your code, but it runs standalone to demonstrate how you possibly should be doing things
var keyValueExists = function(key, value) {
// pseudo junk, this simulates any username starting with b as existing
return new Promise(function(resolve, reject) {
resolve(value.substr(0,1) == 'b'); // barny and betty are dupes, fred and wilma are not
});
}
var addUser = function (newUserInfo) {
// var validationResult = Common._validateUserInfo(newUserInfo);
var validationResult = {isOK: !!~(['fred', 'barny'].indexOf(newUserInfo.userName)), username: newUserInfo.userName}; // dummy code
if (validationResult.isOK) {
return keyValueExists('userName', newUserInfo.userName).then(function (userNameAlreadyExists) {
if (userNameAlreadyExists) {
validationResult = {
isOK: false,
reason: 'Username already exists',
infoWithBadInput: 'userName',
username: newUserInfo.userName
}
} else {
// create new user here
validationResult.userNumber = (Math.random() * 100000000) | 0;
}
return validationResult;
});
}
else {
// this function always needs to return a promise, even if it is resolved/rejected immediately
return Promise.reject(validationResult);
}
}
addUser({userName: 'fred'}).then(function (result) {
console.log(result);
}).catch(function(err) {
console.error(err);
});
addUser({userName: 'wilma'}).then(function (result) {
console.log(result);
}).catch(function(err) {
console.error(err);
});
addUser({userName: 'barny'}).then(function (result) {
console.log(result);
}).catch(function(err) {
console.error(err);
});
addUser({userName: 'betty'}).then(function (result) {
console.log(result);
}).catch(function(err) {
console.error(err);
});

Categories