How to delay a function until another one executes in JavaScript? - javascript

I am trying to write a simple registration function. I keep getting tripped up while trying to verify whether or not a user email already exists. I think that my issue has something to do with asynchronicity. My intent is to hide the registration div and show the profile div once a 201 resonse is received from the server. However, I believe my alert keeps coming up before the response is received. How can I get the code to freeze until after my handlePost is finished? I have tried it in the following ways:
1
registerButton.onclick = function(){
var encodedBody = getRegistrationData();
//if encodedbody then handlepost and show profile etc
if (encodedBody) {
var response = handlePost(encodedBody, 'user');
if (response == '201') {
hideRegistration();
showProfile();
showLoginNav();
showLogin();
// clearFields() need to create this
} else {
alert("Invalid password or email")
console.log('hmm')
}
} else {
alert("Invalid password or email")
}
};
2
registerButton.onclick = function() {
var a = function(callBack){
var encodedBody = getRegistrationData()
var response = handlePost(encodedBody, 'user')
callBack(response)
}
var b = function(response) {
if (response == '201') {
hideRegistration();
showProfile();
showLoginNav();
showLogin();
} else {
alert("Invalid password or email")
}
}
a(b)
}
3
registerButton.onclick = function() {
var encodedBody = getRegistrationData()
if (encodedBody) {
handlePost(encodedBody, 'user').then(function(response) {
if (response == '201') {
hideRegistration();
showProfile();
showLoginNav();
showLogin();
} else {
alert("Invalid password or email")
}
})
} else {
alert("Invalid password or email")
}
};
The following functions are used within the above:
function getRegistrationData() {
var newUserEmail = document.querySelector("#newUserEmail");
var newUserPassword = document.querySelector("#newUserPassword");
var newUserPasswordVerify = document.querySelector('#newUserPasswordVerify');
flag = []
//verify passwords match
if (newUserPassword.value != newUserPasswordVerify.value) {
flag = false
return flag
} else {
flag = true
}
//if user does not exist and passwords match return encoded body
if (flag == true) {
var encodedBody = 'email='+encodeURIComponent(newUserEmail.value)+'&'+'encryptedPassword='+encodeURIComponent(newUserPassword.value)
return encodedBody
}
};
function handlePost(encodedBody, flag) {
if (flag =='user') {
fetch('http://localhost:8080/users', {
body: encodedBody,
method: 'POST',
headers: {
'Content-Type': 'text/plain',
}
})
.then(function(response) {
console.log(response.status)
return response.status
// clearRegistrationFields();
// function to get user profile data
})
}
};
Thanks in advance
Chris

Your handlPost is asynchronous, so you should return a promise if you want to wait for the results:
function handlePost(encodedBody, flag) {
return new Promise(function(resolve, reject) {
if (flag =='user') {
fetch('http://localhost:8080/users', {
body: encodedBody,
method: 'POST',
headers: {
'Content-Type': 'text/plain',
}
})
.then(function(response) {
console.log(response.status)
resolve(response.status)
// clearRegistrationFields();
// function to get user profile data
})
}
});
}
Now your snippet 3 will work, and the response object will be the 'response.status' resolved in the handlePost promise.
Note: you should also handle the promise failure. I'll leave you to work that out.

Related

Execute Multiple HTTP Requests in Synchronous Steps

I have a list of users and I want to make an API call for each one, then if all the results are a specific value for all users make a different API call for each one again checking for a specific value for all users. If all checks out I want to display a success message.
I want to send all of the http calls out for each user, then wait for them all to return before proceeding to the next step.
The following code is what I have so far, the problem is that the success message fires for each user and it loops through each user. I'm struggling to convert each step to accept a list of users.
runAllChecks = function () {
var users = [{
id: 1,
name: "User1"
}, {
id: 2,
name: "User2"
}, {
id: 3,
name: "User3"
}
];
users.forEach(function (user) {
step1(user).then(function (data) {
if (data.result === true) {
return step2(user);
} else {
$scope.userErrors.push('Error on step1 from user ' + user.name);
}
}).then(function (data) {
if (data !== undefined) {
if (data.result === true) {
return step3(user);
} else {
$scope.userErrors.push('Error on step2 from user ' + user.name);
}
}
}).then(function (data) {
if (data !== undefined) {
if (data.result === true) {
alert("done!");
} else {
$scope.userErrors.push('Error on step3 from user ' + user.name);
}
}
});
});
};
var step1 = function (user) {
return $.get("https://api.xyz.com/step1/" + user.id).fail(function (response) {
$scope.httpError = true;
return $q.reject(response);
});
};
var step2 = function (user) {
return $.get("https://api.xyz.com/step2/" + user.id).fail(function (response) {
$scope.httpError = true;
return $q.reject(response);
});
};
var step3 = function (user) {
return $.get("https://api.xyz.com/step3/" + user.id).fail(function (response) {
$scope.httpError = true;
return $q.reject(response);
});
};

Call a function in another javascript function synchronously

I am trying to call checkLoginStatus function in getUserAlbum function, in the getUserAlbum I am catching the response return by checkLoginStatus and on behalf of that response I need to work under the getUserAlbum function.
But the problem is this getUserAlbum function does not wait for the response and execute the next line that I do not want.
Here is my functions:
var accessToken = '';
checkLoginStatus = function () {
FB.getLoginStatus(function(response) {
if (response.status === 'connected') {
accessToken = response.authResponse.accessToken;
console.log(accessToken + ' => in check login status');
return accessToken;
} else {
return false;
}
});
}
getUserAlbum = function () {
var token = checkLoginStatus();
console.log(token + ' => in get album function'); // it log undefined here that is why else part executes.
if(token) {
FB.api(
"/me/albums/", {'accessToken': token},
function (response) {
if (response && !response.error) {
console.log(response);
}
}
);
} else {
alert("You are not logged in");
}
}
Someone can please help me to solve this issue.
FB.getLoginStatus is asynchronous...Use callbacks as response from FB api will be asynchronous. You can not be certain when will it be received.
Your function is executed and control is returned before the response is received hence it will be undefined.
In callbacks, you pass function as argument will will be executed later in the program when needed.
var accessToken = '';
var checkLoginStatus = function(callback) {
FB.getLoginStatus(function(response) {
if (response.status === 'connected') {
accessToken = response.authResponse.accessToken;
callback(accessToken);
} else {
callback(false);
}
});
}
var getUserAlbum = function() {
checkLoginStatus(function(token) {
console.log(token + ' => in get album function'); // it log undefined here that is why else part executes.
if (token) {
FB.api(
"/me/albums/", {
'accessToken': token
},
function(response) {
if (response && !response.error) {
console.log(response);
}
}
);
} else {
alert("You are not logged in");
}
});
}

Angularjs FB login using factory

I am new to angularjs.I am using factories where i have written the fb login code.
And during the last step i am sending all the data to my server where the user is registered in my database and the token is sent.
Here is the code.
'use strict'
APP.factory('authenticationFactory',['ENV','$http','$rootScope', function (ENV,$http,$rootScope) {
return {
socialLogin:function(data){
return $http.post($rootScope.apiURL+'sociallogin',data).then(function (resp) {
if(resp.status == 200) {
return resp.data;
}
})
},
fbLogin: function () {
var FB = window.FB;
var scopes = 'public_profile,email';
var that = this;
FB.login(function (response) {
return that.facebookStatusChangeCallback(response);
}, {scope: scopes});
},
facebookStatusChangeCallback: function(response){
if (response.status === 'connected') {
// Logged into your app and Facebook.
var r = this.facebookApiRequest(response);
console.log(r);
} else if (response.status === 'not_authorized') {
// The person is logged into Facebook, but not your app.
console.log('Please log into this app.');
} else {
// The person is not logged into Facebook, so we're not sure if
// they are logged into this app or not.
console.log('Please log into Facebook.');
}
},
facebookApiRequest: function (authResponse) {
var that = this;
var r = FB.api('/me?fields=id,name,email,gender,first_name,last_name,age_range,link,birthday', function (response) {
var r = FB.api("/" + response.id + "/picture?height=720", function (pictureResponse) {
if (pictureResponse && !pictureResponse.error) {
/* handle the result */
response.profile_pic = pictureResponse.data.url;
response.access_token = authResponse.authResponse.accessToken;
response.provider = 'facebook';
response.devicetoken = '';
response.full_name = response.first_name+' '+response.last_name;
var r = that.socialPluginLogin(response).then(function (resp) {
return that.resp;
});
return r;
} else {
console.log('error while fatching fb pic');
}
});
console.log(r);
});
console.log(that);
},
socialPluginLogin : function (data) {
var resp = this.socialLogin(data).then(function (resp) {
return resp;
});
return resp;
}
};
}]);
I am calling the fbLogin() function from my controller. i need the response from the function socialLogin() so that i can change the state.
Where am i going wrong.??
The answer was pointing in the wrong direction, another try:
Your function fbLogin should return a promise, which can be resolved by socialLogin later. Since fbLogin doesn't return a thing, you don't receive any signal from the completed login.
See this:
// We add $q here
APP.factory('authenticationFactory',['ENV','$http','$rootScope','$q', function (ENV,$http,$rootScope,$q) {
var loginPromise;
return {
socialLogin:function(data){
return $http.post($rootScope.apiURL+'sociallogin',data).then(function (resp) {
if(resp.status == 200) {
// This is your connection to the controller
loginPromise.resolve(resp.data);
return resp.data;
}
})
},
fbLogin: function () {
var FB = window.FB;
var scopes = 'public_profile,email';
var that = this;
FB.login(function (response) {
return that.facebookStatusChangeCallback(response);
}, {scope: scopes});
// Create and return a promise
loginPromise = $q.defer();
// EDIT: My fault, return the promise:
return loginPromise.promise;
},
//...
And add this to the controller:
authenticationFactory.fbLogin().then(function(data){
// Check it out:
console.dir(data);
})
Additional things you should consider:
Define your functions in the function body, not in the return statement. You can eliminate that=this this way
Only return the API, not all the functions
Read up on promises, they are the way to go in the angular world. You might as well use callbacks, but those are tedious to handle.
Change your socialLogin function to below, your function would return a promise object which you can consume in socialPluginLogin via then which you are already doing.
socialLogin:function(data){
return $http.post($rootScope.apiURL+'sociallogin',data)
},

How to return authRequired and WL.Server.invokeHttp value to client side using web services in Adapter based authentication with worklight?

Edit : I am using Adapter based authentication with worklight and angularJs. on click of login button i'm calling submitLogin procedure and pass the username and password in parameter as mention below. my query is after invocation of adapter how i'll return the authRequired value and WL.Server.invokeHttp(input) response simultaneously to the client side. i also mention challenge handler for authentication in login services code
adapter code:
function submitLogin(username, password){
WL.Logger.debug("username: "+username);
var payload = {
"Header": {
"header": {
"myschemeName": "",
"myserviceVersion": "0.00",
"myinternalId": "",
"myexternalId": "",
"mysource": "web",
"mydestination": "test",
"myuserId": ""
}
},
"Body": {
"login": {
"username": username,
"password": password
}
}
}
var input = {
method : 'post',
returnedContentType : 'jsonp',
path: '/mywebservices/login',
headers : {
'Accept-Encoding': 'gzip,deflate',
'Content-Type': 'application/json'
},
body: {
'contentType' : 'application/json',
'content' : payload
}
};
return {authRequired: false, WL.Server.invokeHttp(input);};
}
login services:
angular.module('my.services')
.factory('loginServices', function($http, $q, $rootScope) {
'use strict';
//worklight
var realm = "AdapterAuthRealm";
var securityTest = "Master-Password";
//offline
var offlineAuthed = false;
var tempUser = {};
//user object
var userObj = {};
//login popup
userObj.dialog = false;
//login error message
userObj.authError = "";
//logged in boolean
userObj.loggedIn = null;
var defunct = null;
//change handler
var ch = WL.Client.createChallengeHandler(securityTest);
//first response after protected call
ch.isCustomResponse = function(response){
console.log("challenge handler -- isCustomResponse");
if (!response || !response.responseJSON || response.responseText === null) {
return false;
}
if (typeof(response.responseJSON.authRequired) !== 'undefined'){
return true;
} else {
return false;
}
};
//when isCustomResponse returns true
ch.handleChallenge = function(response){
console.log("challenge handler -- handleChallenge");
var err = response.responseJSON.errorMessage;
var req = (String(response.responseJSON.authRequired) == "true");
if (!req){ //successful login request
console.log("-> login success!");
//create offline auth credentials
createOfflineAuth();
//call the success function of initial adapter call
//ch.submitSuccess();
}
//error message
userObj.authError = "";
if (err != null){
userObj.authError = "* " + err;
}
//login boolean
userObj.loggedIn = !req;
//show login popup
userObj.dialog = req;
//update scope
$rootScope.$apply();
//resolve original function if it exists
if (defunct != null){
defunct.resolve(userObj.loggedIn);
}
};
//** Offline **//
//check if user is online
function checkOnline(){
var def = $q.defer();
WL.Client.connect({
onSuccess: function(){
console.log("** User is online!");
def.resolve(true);
},
onFailure: function(){
console.log("** User is offline!");
def.resolve(false);
},
timeout: 1000
});
return def.promise;
}
//creates an offline authentication object
function createOfflineAuth(){
console.log("creating offline auth");
//encrypt the user object
var encyptedUser = md5(angular.toJson(tempUser));
//save to local storage
localStorage.setItem(tempUser.username, encyptedUser);
//clear tempUser
tempUser = {};
}
//offline login
function offlineLogin(){
userObj.authError = "";
//encrypt the tempuser object
var match = md5(angular.toJson(tempUser));
var savedAuth = localStorage.getItem(tempUser.username);
//check if matching the saved one
offlineAuthed = (savedAuth == match);
console.log("Login successfull: " + offlineAuthed);
//error - mismach
if (!offlineAuthed){
userObj.authError = "* Wrong login details.";
}
//error - if the user has never authenticated with the server
if (savedAuth == null){
userObj.authError = "* You have to go online first.";
}
//login boolean
userObj.loggedIn = offlineAuthed;
//show login popup
userObj.dialog = !offlineAuthed;
return offlineAuthed;
}
//-- APIS to the rest of the app --//
return {
getUser: function(){
return userObj;
},
initUser: function () {
console.log("-> getting user state data");
var def = $q.defer();
checkOnline().then(function (onl){
if (onl){ //online
WL.Client.updateUserInfo({onSuccess: function(){
userObj.loggedIn = WL.Client.isUserAuthenticated(realm);
def.resolve();
}});
} else { //offline
userObj.loggedIn = false;
def.resolve();
}
});
return def.promise;
},
checkUser: function () {
var def = $q.defer();
checkOnline().then(function (onl){
if (onl){ //online
userObj.loggedIn = WL.Client.isUserAuthenticated(realm);
} else { //offline
userObj.loggedIn = offlineAuthed;
}
userObj.dialog = !userObj.loggedIn;
//check success
if (!userObj.loggedIn){
//save the deferred for challengehandler
defunct = def;
} else {
//resolve
def.resolve(true);
}
});
return def.promise;
},
login: function (user,pass){
//promise
var logindef = $q.defer();
//tempuser
tempUser = {username:user, password:pass};
userObj.user = user;
checkOnline().then(function (onl){
if (onl){ //online
console.log("attempting online login");
var options = {
parameters:[user, pass],
adapter:"myAdapter",
procedure:"submitLogin"
};
ch.submitAdapterAuthentication(options,{
onSuccess: function(){
console.log("-> submitAdapterAuthentication onSuccess!");
//update user info, as somehow isUserAuthenticated return false without it
WL.Client.updateUserInfo({onSuccess: function(){
//return promise
logindef.resolve(true);
}});
}
});
} else { //offline
console.log("attempting offline login");
logindef.resolve(offlineLogin());
}
});
return logindef.promise;
}
};
});
I am trying to decrypt your question. It's not clear at all.
However there is already one thing that jumps out.
In your adapter you finished with:
return {authRequired: false, WL.Server.invokeHttp(input);};
You saying authRequired false even before checking if the credentials are valid?
You are supposed to parse the content of the results of WL.Server.invokeHttp(input) inside the adapter, decide if the credentials are valid.
If they are valid use setActiveUser before returning authRequired false.
Don't return the content of WL.Server.invokeHttp(input) to the client. This is meant for the adapter to parse.
See this tutorial: https://developer.ibm.com/mobilefirstplatform/documentation/getting-started-7-1/foundation/authentication-security/adapter-based-authentication/

jQuery return $.post callback through parent function [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Return Value from inside of $.ajax() function
Take the following function for example:
function($data) {
$.post(
url,
{
'data': $data
},
function(response){
return response;
}
);
}
How could I make the parent function: function($data) { ... } return response?
I am unable to put my the rest of my logic into the post callback due to the nature of my script. (see below)
var methods = {
'email' : function(field) {
var value = field.val();
var response = false;
field.addClass("loading");
$.post(
ajaxData.url,
{
'action':'validate_form',
'value': value,
'method': field.data('method')
},
function(response){
return response;
}
).complete(function() {
field.removeClass("loading");
});
},
'password' : function(field) {
var value = field.val();
var response = {};
if (value.length < 8) {
response.result = false;
response.message = 'Your password must be a minimum of 8 characters';
} else {
response.result = true;
response.message = false;
}
return response;
},
'verify_password' : function(field, dependancies) {
var value = field.val();
var response = {};
if (value != dependancies["password"].val()) {
if (!dependancies["password"].val() || !value) {
return false;
}
response.result = false;
response.message = 'Passwords do no match';
} else {
response.result = true;
response.message = false;
}
return response;
}
}
Where each property of methods is a function which may be called and the return value is used later in the script.
var response = methods[field.data('method')](field, field.data('dependancies'));
As A of AJAX stands for Asynchronous, so you can't return like you want. You can try with a callback function like below:
function($data, callback) {
$.post(
url,
{
'data': $data
},
function(response){
return callback(response);
}
);
}
For example:
var myObj = {
myfunc: function($data, callback) {
$.post(
url,
{
'data': $data
},
function(response){
return callback(response);
}
);
}
}
myObj.myfunc($data, function(response) {
// process here with response
});

Categories

Resources