Call a function in another javascript function synchronously - javascript

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");
}
});
}

Related

How to delay a function until another one executes in 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.

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);
});
};

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 call a function after completion of all requests

I have two AJAX requests one after another-
var firstResult;
var secondResult;
FirstAjaxrequest({
callback: function (options, success, response) {
if(success)
{
firstResult = true;
}
else
{
firstResult = false;
}
}
});
SecondAjaxrequest({
callback: function (options, success, response) {
if(success)
{
secondResult= true;
}
else
{
secondResult= false;
}
}
});
DisplayMessage(); // This function should display a message depending on
FirstResult and secondResult
You could create a variable for each request, signifying a successful request. Change this variable for each request respectively, when a successful request is made, then call your function.
Within your function simply check both variables, if they're both true, then both requests were successful, otherwise at least one was not and the if() condition will be false.
var firstResult = false,
secondResult = false;
FirstAjaxrequest({
callback: function (options, success, response) {
if(success) {
firstResult = true;
DisplayMessage();
}
}
});
SecondAjaxrequest({
callback: function (options, success, response) {
if(success) {
secondResult= true;
DisplayMessage();
}
}
});
function DisplayMessage(){
if(firstResult && secondResult){
//Both requests successful
} else {
//Either still waiting for a request to complete
// or a request was not successful.
}
}
There might be a better way to do it in EXTJS, but a plain JS solution is
var firstResult;
var secondResult;
var reqCount = 2;
var returnedCount = 0;
function isDone () {
returnedCount++
if ( returnedCount === reqCount ) {
console.log(firstResult, secondResult);
}
}
FirstAjaxrequest({
callback: function (options, success, response) {
if(success)
{
firstResult = true;
}
else
{
firstResult = false;
}
isDone();
}
});
SecondAjaxrequest({
callback: function (options, success, response) {
if(success)
{
secondResult= true;
}
else
{
secondResult= false;
}
isDone();
}
});
Give this a try
FirstAjaxrequest({
callback: function (options, success, response) {
if(success)
{
firstResult = true;
}
else
{
firstResult = false;
}
SecondAjaxrequest({
callback: function (options, success, response) {
if(success)
{
secondResult= true;
}
else
{
secondResult= false;
}
DisplayMessage(); // Now we have access to first and second result as the
//as the second request is within the scope of the first request
},
scope: this // We can pass the first request to the second request as the context
});
}
});
After the completion of each request, you should check if the result of the other one is received or not.
Some thing like this:
var result1 = null;
var result2 = null;
function DoAjax() {
$.get(url1, {}, function (data) {
result1 = data;
DoSth();
});
$.get(url2, {}, function (data) {
result2 = data;
DoSth();
});
}
function DoSth() {
if(result1 != null && result2 != null) {
//...
}
}
Warning: jQuery answer. I'm not sure if extjs has similar support for Deferreds and Promises.
This is a perfect opportunity to learn about jQuery Deferred:
$.when(firstAjaxrequest(...), secondAjaxrequest(...))
.then(function (firstResult, secondResult) {
...
});
This assumes your firstAjaxrequest and secondAjaxrequest functions both return Deferred or Promise objects, such as those returned by $.ajax.

How can I tell when a JavaScript asynchronous function ends?

I am trying to determine through some flag when this asynchronous function ends.
This is how I call my function:
// Calling the function in a loop
for (var i=0,l=myIds.length; i<l; ++i) {
install(pageId, myIds[i], apps_num[''+myIds[i]], <?php echo $this->comid ?>, '<?php echo $this->site_url; ?>');
}
And this is my function:
install: function(pageId, appId, app_num, com_id, siteurl) {
FB.getLoginStatus(function(response) {
// Checking if connected to Facebook
if (response.status === 'connected') {
var uid = response.authResponse.userID;
console.log(response.authResponse);
var userAccessToken = response.authResponse.accessToken;
// Get page access token
FB.api('/'+pageId+'?fields=access_token='+userAccessToken, function(response) {
var pageAccessToken = response.access_token;
// Get information if user got this application
FB.api('/'+pageId+'/tabs/'+appId+'?access_token='+pageAccessToken,
function(data) {
if (data.data.length < 1) {
console.log("Not installed, Installing...");
// Install the application
var params = {};
params['app_id'] = appId;
FB.api('/'+pageId+'/tabs?access_token='+pageAccessToken, 'post', params, function(response) {
if (!response || response.error) {
console.log("Error Installing!");
}
else {
console.log("Installed :)");
}
});
}
else {
console.log("Already installed.");
}
});
});
}
else
if (response.status === 'not_authorized') {
console.log("the user is logged in to Facebook, but not connected to the app.");
}
else {
console.log("the user isn't even logged in to Facebook.");
}
});
}
How can I solve this issue? I tried to use static variables, but I wasn't able to call them inside the asynchronous function..
The usual thing is to have any code that needs to know the outcome of an asynchronous call pass a function reference into the call, which the function then calls when it's done (a "callback").
So in your case, you'd add a callback parameter to your install function:
install: function(pageId, appId, app_num, com_id, siteurl, callback)
// here ------------^
...and then call it when appropriate from the callbacks you're passing into FB.getLoginStatus and/or FB.api, e.g. something like this:
install: function(pageId, appId, app_num, com_id, siteurl, callback) {
FB.getLoginStatus(function(response) {
// checking if connected to facebook
if (response.status === 'connected') {
var uid = response.authResponse.userID;
console.log(response.authResponse);
var userAccessToken = response.authResponse.accessToken;
// get page access token
FB.api('/'+pageId+'?fields=access_token='+userAccessToken, function(response) {
var pageAccessToken = response.access_token;
// get information if user got this app
FB.api('/'+pageId+'/tabs/'+appId+'?access_token='+pageAccessToken,
function(data) {
if (data.data.length < 1) {
console.log("Not installed, Installing...");
// install the app
var params = {};
params['app_id'] = appId;
FB.api('/'+pageId+'/tabs?access_token='+pageAccessToken, 'post', params, function(response) {
if (!response || response.error) {
callback(false, "Error installing");
console.log("Error Installing!");
} else {
callback(true, "Installed");
console.log("Installed :)");
}
});
}
else {
callback(false, "Already installed.");
console.log("Already installed.");
}
});
});
} else if (response.status === 'not_authorized') {
callback(false, "Logged in but not connected.");
console.log("the user is logged in to Facebook, but not connected to the app.");
} else {
callback(false, "Not logged in.");
console.log("the user isn't even logged in to Facebook.");
}
});
}
There I've given the callback function two arguments: A boolean saying whether the installation was performed, and a status message.
First, you add an extra param to your function, that will receive a function object
install: function(pageId, appId, app_num, com_id, siteurl, callbackFunction) {
Then, inside the function install, after
console.log("Installed :)");
you add
callbackFunction();
This way, when you call the install function:
for (var i=0,l=myIds.length; i<l; ++i) {
install(pageId, myIds[i], apps_num[''+myIds[i]], <?php echo $this->comid ?>, '<?php echo $this->site_url; ?>', function(){
//do whatever you want;
});
}
jQuery does it by letting the user determine how a function should react when a function is finished. This means, putting a function as a parameter. This is called a callback
function install(pageId, appId, app_num, com_id, siteurl, pCallback) {
//Doing cool stuff.
//OK, I am finished.
pCallback(a, b, c)
}
function lefinish(a, b, c) {
alert(b);
}
// Calling install
install(pageId, appId, app_num, com_id, siteurl, lefinish)
As an added bonus, if you really need to know exactly what happened, you can put multiple functions in it, depending on the success of your first function
function install(pageId, appId, app_num, com_id, siteurl, pCallback) {
//Doing awesome stuff
if (response.status === 'connected') {
if (typeof(pCallback.onConnect) == 'function') {
pCallback.onConnect(a,b,c);
}
}
else
if (response.status === 'not_authorized') {
if (typeof(pCallback.onNoAuth) == 'function') {
pCallback.onNoAuth(a,b,c);
}
}
else {
if (typeof(pCallback.onNotLoggedIn) == 'function') {
pCallback.onNotLoggedIn(a,b,c);
}
}
}
function lefinish(a, b, c) {
alert(b);
}
// Calling install
install(pageId, appId, app_num, com_id, siteurl, {
'onConnect': function(a,b,c) {}, //Anonymous function
'onNoAuth': lefinish //A predefined function
// does not produce an error if onNotLoggedIn is not defined because of typeof().
})

Categories

Resources