How can I tell when a JavaScript asynchronous function ends? - javascript

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().
})

Related

Jquery Terminal register & login

I have question, i want user register then login but here it's error anyone can help me ? i saw the documentation . here is link of the documentation jquery termi[jquery terminal]1nal
here is my script:
if (command == 'register') {
term.push(function(command, term) {
term.pause();
$.ajax({
url: "register.php",
type: "post",
data: {data_register : command },
success: function (msg) {
term.echo(yellow('Data Saved Successfully !'));
term.resume();
},
error: function(jqXHR, textStatus, errorThrown) {
term.resume();
}
});
},
{
prompt: " > "
});
} else if (command == 'login'){
login: function(user, password, callback) {
if (user == 'demo' && password == 'secret') {
callback('SECRET TOKEN');
} else {
callback(null);
}
}
}
this line's error :
else if (command == 'login'){
login: function(user, password, callback) {
if (user == 'demo' && password == 'secret') {
callback('SECRET TOKEN');
} else {
callback(null);
}
}
}
Thank you
You have invalid JavaScript you have label and function declaration, which should be put in an object like this:
var x = {
login: function() {
}
};
which should be part of object in second argument which is options object.
.terminal(function(command) {
if (command === 'register') {
}
}, {
login: function(...) {
...
}
});
and for your exact problem on having login command, that login you in, you need to invoke login method like this:
} else if (command == 'login'){
term.login(function(user, password, callback) {
// to get the token you should send user and password to the server
if (user == 'demo' && password == 'secret') {
callback('SECRET TOKEN');
} else {
callback(null);
}
});
} else if (term.token()) {
// here are commands that will only work after user login
// but you need to know that user may add token in developer tools
// so you should use additional check if token is valid by sending token
// to the server, or if you're invoking command on the server then just
// send the token and validate it there
} else {
term.error('invalid command');
}

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.

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

Backbone router using jQuery $.get() promise to determine logged in state of user not working as expected

I'm trying to use a jQuery promise to make authenticated.done wait until the $.get() in .isAuthenticated returns, but I'm not getting the result I was expecting... the function inside authenticated.done runs before the preceding $.get() returns and thus does not work. Am I doing something wrong or am I going about this in entirely the wrong way?
isAuthenticated : function() {
// make a request to the server and see if the response is a login form or not
// this should just return true or false, not actually handle login etc
var authenticated = false;
console.log("authenticating...");
var ready = Promise.from(null);
$.get("/loggedin")
.then(function(data, textStatus) {
var rtnVal = false;
if (textStatus == "success" && !(data instanceof Object)) {
console.log("failure returned");
} else {
console.log("success returned");
rtnVal = true;
}
return rtnVal;
})
.done(function(result) {
authenticated = result;
});
return ready.then(function () {
return authenticated;
})
},
render: function (view) {
if(this.currentView) this.currentView.destroy();
var authenticated = this.isAuthenticated();
authenticated.done(function (response) {
if (response == true) {
console.log("Authentication success!");
// set the currentView
this.currentView = view;
// render the new view
this.currentView.render();
// set the view's menu items
if (this.currentView.navLink !== undefined) {
$(this.currentView.navLink).addClass("active");
}
} else {
console.log("Authentication failed...");
view = new app.LoginView();
view.render();
this.currentView = view;
}
});
return this;
}
And the console output:
authenticating... router.js:45
Authentication failed... router.js:89
success returned router.js:55
Here's what your code should look like using jQuery's Deferred/Promise objects:
{
authenticate: function () {
var authentication = $.Deferred();
$.get("/loggedin")
.then(function (data, textStatus) {
if (textStatus === "success" && !(data instanceof Object)) {
authentication.resolve(data, textStatus);
} else {
authentication.reject(data, textStatus);
}
});
return authentication.promise();
},
render: function (view) {
if (this.currentView) this.currentView.destroy();
this.authenticate()
.done(function (data, textStatus) {
this.currentView = view;
this.currentView.render();
$(this.currentView.navLink).addClass("active");
})
.fail(function (data, textStatus) {
view = new app.LoginView();
view.render();
this.currentView = view;
});
return this;
}
};
Notes:
since then is called regardless of success or failure of the GET request you don't need a fail callback.
I've renamed the function to the more appropriate authenticate, because it is an action, not a state
jQuery does not care if you pass undefined to it, so your if (this.currentView.navLink !== undefined) check is superfluous
You might want to use data and textStatus in the authentication callbacks somehow. If you don't need them, call resolve() or reject() without arguments.
I do not know what is Promise object that you are using, but using standard jquery deferred object the code will look:
isAuthenticated : function() {
// make a request to the server and see if the response is a login form or not
// this should just return true or false, not actually handle login etc
var authenticated = $.Deferred();
console.log("authenticating...");
$.get("/loggedin")
.then(function(data, textStatus) {
if (textStatus == "success" && !(data instanceof Object)) {
console.log("failure returned");
authenticated.reject();
} else {
console.log("success returned");
authenticated.resolve();
}
}, function () {
authenticated.reject();
});
return authenticated;
},
render: function (view) {
if(this.currentView) this.currentView.destroy();
var authenticated = this.isAuthenticated();
authenticated.done(function (response) {
if (response == true) {
console.log("Authentication success!");
// set the currentView
this.currentView = view;
// render the new view
this.currentView.render();
// set the view's menu items
if (this.currentView.navLink !== undefined) {
$(this.currentView.navLink).addClass("active");
}
} else {
console.log("Authentication failed...");
view = new app.LoginView();
view.render();
this.currentView = view;
}
});
authenticated.fail(function () {console.log('failed')});
return this;
}

Categories

Resources