Javascript can't set variable value - javascript

I'm trying to get this function to set sortedScores to a value... whenever i do console.log anywhere it seems to store the values right, but it can't actually set sortedScores properly...
function facebook(sortedfriends) {
var myID;
var access_token;
FB.init({
appId : something,
status : true,
cookie : true,
xfbml : true,
});
FB.getLoginStatus(function(response, sortedfriends) {
if(!response.session) {
FB.login(function(response) {
myId = response.session.uid;
access_token = response.session.access_token;
//does stuff
if (!response.session) {
console.log('User cancelled login or did not fully authorize.');
}
});
}
else if(response.session) {
myId = response.session.uid;
access_token = response.session.access_token;
var D = new Array();
this.access_token = access_token;
FB.api('/me/feed?access_token=' + access_token + '&limit=100', function(response, sortedfriends) {
for( i=0; i<response.data.length; i++) {
var msg = response.data[i];
D.push(msg);
}
sortedfriends = somefunction(D, myID);
//i know somefunction works because if i do console.log(sortedfriends) it shows me the right values...
});
}
});
}
when i try
var friends;
facebook(friends);
friends is just undefined... halp?

It is not clear where you are trying to access sortedfriends, but I'm guessing that your issue is that the Facebook login is asynchronous, so the response comes some time later after the facebook function has completed. Thus, if you're trying to use the sortedfriends data right after you call the facebook function, the data will not be there yet because the login call has not completed yet.
The only way to use the sortedfriends data is from the success handler to the login call (where your console.log already verifies that the data is there). If you want to use it in other code, then call that other code from the success handler to the login call. You cannot call that code right after calling the facebook function.
This logic will not work because of the asynchronous nature of the login call (it hasn't completed when the facebook call returns and execution continues after it:
var sortedfriends = [];
facebook(sortedfriends);
// use sortedfriends here
Instead, you have to do this type of structure:
var sortedfriends = [];
facebook(sortedfriends);
// nothing executes here
And, inside your facebook call where you have this, add a function call to whatever code you want to use the sortedfriends data:
else if(response.session) {
myId = response.session.uid;
access_token = response.session.access_token;
var D = new Array();
this.access_token = access_token;
FB.api('/me/feed?access_token=' + access_token + '&limit=100', function(response, sortedfriends) {
for( i=0; i<response.data.length; i++) {
var msg = response.data[i];
D.push(msg);
}
sortedfriends = somefunction(D, myID);
//i know somefunction works because if i do console.log(sortedfriends) it shows me the right values...
// call the rest of your code here that will use sortedfriends
doSomethingWithSortedFriends(sortedfriends);
});

javascript functions do not change incoming references. You cannot pass undefined and expect it will become defined after the function executes.
Instead, you should make your sortedFriends a global variable and not pass it as function parameter. Please note, that the value of sortedFriends will be set after the ajax query inside getLoginStatus is executed, so you will not be able to use it immediately after you execute your facebook function.

Related

Passing data between controllers in MVC Javascript

I am using Express and Node to build an app.
I have a route called '/new-poll' and '/poll-create'
//The poll-create route will give the user the option of creating a poll
app.route('/poll-create')
.get(function(req, res) {
res.sendFile(path + '/public/pollcreation.html');
});
//This is the route for creating a new poll by authenticated users. Authentication still needs to be added.
app.route('/poll-create')
.post(function(req, res) {
console.log('inside poll-create post request');
console.log(req.body);
serverHandler.newPoll(req, res, db, function(id) {
console.log('It worked');
req.session.poll_id = id;
res.json(id);
});
});
//The above response will redirect to this route, and here is where the poll data will be served up
app.route('/new-poll')
.get(function(req, res) {
console.log('Inside get request for new poll');
console.log(req.session.poll_id);
res.sendFile(path + '/public/pollvisualization.html');
});
//This is the route for making a post request to the same URL. Specifically to obtain the document inserted previously through creating a new poll
app.route('/new-poll')
.post(function(req, res) {
console.log('Inside new poll post');
serverHandler.check(db, req.session.poll_id, function(err, doc) {
if (err) {
console.log('There is an error');
throw err;
}
if (doc) {
res.json(doc); //send the json document generated by the poll creation by mongoDb to pollvisualizationClient.js through ajax-functions.js
}
});
});
Now, I have 2 controllers, controllerData and controllerNonData.
controllerData passes in data to the above POST request using an AJAX call. controllerNonData needs to access the data passed to the POST request by controllerData.
How can I do this in the simplest possible manner? Essentially, my question boils down to what is the easiest way to pass data between view controllers in Express and Node?
The way I'm doing it right now is, I make a POST request with data from controllerData and then make a POST request without data from controllerNonData and then try to differentiate between the two calls in the POST request. But, it seems like a giant pain!
NOTE: I am not using AngularJS in my app. Mentioning this because all the answers I have seen on StackOverflow mention ways to do this in AngularJS.
EDIT:
Code for controllerData
(function() {
$(document).ready(function() {
if (typeof FB !== 'undefined' && FB !== null) { //this if statement is to ensure FB object loads before doing anything else
FB.Event.subscribe('auth.authResponseChange', function() {
FB.getLoginStatus(function(response) {
var data = {}; //setting up the data object to fill with objects
$('.submit-butt').on('click', function() {
data.formData = $('form').serializeArray(); //this is the form data from the form
data.facebookData = response.authResponse; //facebook object data
console.log(data);
data = JSON.stringify(data); //this is done to pass the data and parse it through body parser. Not sure why it works this way.
ajaxFunctions.ready(ajaxFunctions.ajaxRequest('POST', appUrl + '/poll-create', data, function() {
window.open('https://fcc-votingapp-redixhumayun.c9users.io/new-poll', '_self');
}));
return false; //setting this statement to false ensures that the form data does not automatically submit independent of the AJAX call
});
});
});
}
else {
location.reload(); //reloads the page in case the if statement is not satisfied.
}
});
})();
Code for controllerNonData
(function() {
var value; //variable to store the value of the radio option selected
var custom_flag = false; //flag variable to check whether Custom radio button was selected
//This is where the AJAX request is initialized
ajaxFunctions.ready(ajaxFunctions.ajaxRequest('POST', appUrl + '/new-poll', null, function(data) {
//Parsing the data into JSON format below
$(document).ready(function() {
//this is the form data that has been provided via the AJAX request
data = JSON.parse(data);
console.log(data);
var options_count = data[0].options_counter; //this variable stores the options_counter, that is the number of options
var options_array = getSeperatedOptions(data[0].options);
var options_length = Object.keys(options_count).length; //finding out the length of the options_counter object in this line
//updating the header element
$('h1').html(data[0].title);
//Invoking the function that will create all of the options required by the user
createOptions(options_length, options_array);
//This method here checks to see if the user has selected Custom as their option
$('.radio-options').on('click', function() {
var entered_value = getEnteredOption(options_length); //calling this function to check if Custom has been chosen.
if (entered_value == options_length) { //parseInt of entered_value will return a NaN. Use this to check against the number that is returned for parseInt of the other radio buttons
$('.custom-div').show();
custom_flag = true; //set the custom flag to true here because Custom radio button was selected
}
});
$('.btn-danger').on('click', function() {
ajaxFunctions.ready(ajaxFunctions.ajaxRequest('POST', appUrl + '/new-poll/delete-poll', data[0]._id, function(data) {
console.log('This is data: '+data); //data contains the number of documents deleted
}));
});
//Submit button event click handler
$('.submit-butt').on('click', function() {
//if statement decides whether the radio button selected was the Custom radio button
if (custom_flag == true) {
var entered_value = $('.custom-text').val();
value = entered_value; //assigning the local entered_value to a global value variable to use in the next AJAX function
}
//else if statement decides whether a radio option button is checked or not! Fires only if Custom not selected
else if ($('.radio-options').is(':checked')) {
var entered_value = getEnteredOption(options_length); //Function call to get option entered by user. Returns the value of the radio button
value = entered_value; //assigning the local entered_value to a global value variable to use in the next AJAX function
}
//Fire this else statement if no option is selected but Submit button is clicked
else {
window.alert('You need to choose an option before trying to submit');
}
if (value.length > 0) {
var dataToPass = {}; //defining this object to pass data as JSON
dataToPass.value = value;
dataToPass = JSON.stringify(dataToPass); //stringify data to pass it through without error
ajaxFunctions.ready(ajaxFunctions.ajaxRequest('POST', appUrl + '/new-poll/option-entered', dataToPass, function(data) {
//This object contains the returned value from the above AJAX call
data = JSON.parse(data);
var optionsArray = getSeperatedOptions(data.value.options); //Keep the difference between optionsArray and options_array in mind AT ALL TIMES!
//This function is used to convert the options_counter object to an array so that it can be used to render the chart using ChartJS
var options_counterArray = convertOptionsCounterToArray(data.value.options_counter);
//call to function to create chart here
createChart(optionsArray, options_counterArray);
}));
}
else {
window.alert('Hi!');
}
});
});
}));
})();
EDIT: I have also updated my routes to use sessions.
So I am assuming that your Controllers are on the client side. http is a stateless protocol. So in order to pass data between states, you need to implement some kind of caching mechanism. There are a few ways to do this:
Use HTML5 localStorage or sessionStorage API directly, based on the length of time you want to save the data. Make sure you clear the storage once you're done with the data, to prevent hitting the 5MB limit. Using localStorage will allow you to use the data till it is manually cleared. sessionStorage will live as long as the tab is open.
Use some other kind of client side storage like Web SQL
If you want to store data within a page reload cycle (i.e. you will lose data once you reload the page), you can create a Javscript singleton function and inject it into both of your AJAX calls as a dependency, and store your response in that object. This is similar to what happens in AngularJS's Service providers. This is cleaner than the other two approaches, but is of course, shorter lived (unless used on conjunction with one of the above Storage APIs)
Creating singletons in Javascript
var UserStore = (function(){
var _data = [];
function add(item){
_data.push(item);
}
function get(id){
return _data.find((d) => {
return d.id === id;
});
}
return {
add: add,
get: get
};
}());

multiple calls to ajax simultaneously

I'm trying to make multiple calls to Ajax, i have fields like time intervals and no of calls to ajax under that time period. Now the problem is, while making multiple calls to same Ajax, there may be chances of merging of data with the other data that were send to Ajax earlier. I am not sure that it will happen.
Here my Ajax call.
callAjax = function () {
var dataIn = inObj.data || {};
var successFunc = inObj.success || function () {};
var passOn = inObj.passOn || {};
var myParams = {drape:1,type:'GET'};
myParams.url = this.homeComingUrl;
$.extend(myParams,params);
var data = this.fillAction(action,dataIn);
if (myParams.drape) { vidteq.utils.drapeSheer(action); }
var that = this;
var magicCall = $.ajax({
url:myParams.url,
type:myParams.type,
data:data,
success: function (response) {
// TBD we need better error handling
if (myParams.drape) { vidteq.utils.undrapeCurtain(action); }
successFunc(response,passOn);
},
error:function(response) {
if (myParams.drape) { vidteq.utils.undrapeCurtain(action); }
that.gui.io.handleError(response);
}
});
}
saveEvents = function () {
this.commitEditingEvent();
var dataEvents = this.collectEventsToSave();
//$('#calendar').fullCalendar('removeEvents');
var that = this;
if (vidteq.eTrainer==1) {
dataEvents = arguments[0];
}
if (!dataEvents.length) { alert("Nothing to save");return; }
this.callAjax('updateEvents',{
data : { events : JSON.stringify(dataEvents) },
success : function (response,passOn) {
that.handleGetEvent(response,passOn);
}
},{type:'POST'});
}
This may not be required for understanding the problem.
If any body can explain how Ajax handles multiple calls, then it'll really helpful.
First line, your anonymous function isn't saved and isn't ran. Then. In each function, what does this refer to ? What is this context ? Is this window or do you call your function like saveEvents.apply( jQuery ) ?
JavaScript is powerful, when your want to run XMLHttpRequest (Ajax uses it), scripts are called when an event happen, like "server is found", "request is send", "file is reading", "file loaded"... for each state of your request. Ajax by jQuery help you to request asynchronous. You can request as many Ajax request as you would like in the same time. The important is to create a function happen in success case.
In this success function, you receive data, you compute it, then this function may call another Ajax request, and so on. When you chain requests like this to get the same file, we call it Ressource.
Ressource uses Ajax which uses XMLHttpRequest.
you need to do asynic :false in your ajax method
function isLoggedIn() {
var isLoggedIn;
$.ajax({
async: false,
// ...
success: function(jsonData) {
isLoggedIn = jsonData.LoggedIn
}
});
return isLoggedIn
}

ajax complete callback function is never called

I'm using Django.
I have the following code
var done_cancel_order = function(res, status) {
alert("xpto");
};
var cancel_order = function() {
data = {};
var args = {
type:"GET",
url:"/exchange/cancel_order/"+this.id,
data:data,
complete:done_cancel_order
};
$.ajax(args);
return false;
};
The function var cancel_order is called when I press a button on the page. That url when accessed is does some things on the server side, which I can check indeed are done, and then returns a json specifying whether or not the request was successful. You get:
{'status':200, 'message':'order canceled'}
The problem is that the callback is never called. I would like to have the callback display to the user the thing that was returned from the server. But even the first alert("xpto") inside the callback is never executed. Why is that?
EDIT:
I have checked that this code:
var cancel_order = function() {
data = {};
var args = {
type:"GET",
url:"/exchange/cancel_order/"+this.id,
data:data,
complete: function() { alert("xpto"); }
};
$.ajax(args);
return false;
};
displays the same behavior as described above: everything goes great on the server side, but the callback isn't called.
Be sure nothing is messing with your debug tools [e.g. console.log], it may end up wrecking your js code, delivering unexpected results.
Why don't you change it to this:
function done_cancel_order (res, status) {
/* remains same */
};
I hope, this one would work for you!
Or just simply:
complete: alert("xpto");

JavaScript function within a function - returning an object

I would like to call a function within a function and have this inner function return an object. I am using a JSONRequest function that I created myself so just assume that the request fetches an array of roles. Here is the code:
(users = function(){
this.getUserRoles = function(){
var params = {};
var json = new JSONRequest(function(data){
rolesObj = data['roles'];
return rolesObj;
}, 'get_roles', params);
}
});
Then I call the following but it returns undefined:
var cls = new users();
alert(cls.getUserRoles().length);
ajax requests are asynchronous so you're not going to get a return value from them. You do, however, receive a callback when they complete so you can pass your "return" value into a callback.
Here is an example of your code re-written to use a callback:
this.getUserRoles = function(completionCallback){
var params = {};
var json = new JSONRequest(function(data){
rolesObj = data['roles'];
completionCallback(rolesObj);
return rolesObj;
}, 'get_roles', params);
}
and then using it:
var cls = new users();
cls.getUserRoles(function(roles) {
alert(roles.length);
});
The rolesObj is passed into the callback function once the JSON request completes.
Your getUserRoles function doesn't return anything. It invokes an asynchronous JSON request, and the success callback for that request returns something.
There is no way to make an asynchronous request in a function and have the function synchronously return a value from the request. The request will take an unknown amount of time, and the requesting function will return as soon as the request has been sent. The value won't have arrived back from the server yet.

How to use YAHOO.util.Connect.asyncRequest and return results?

I'm using YAHOO.util.Connect.asyncRequest to get data from database, here is the code :
function getCountArticle(contentCurValue) {
var handleSuccess = function (res) {
var countPubmed = YAHOO.lang.JSON.parse(res.responseText);
var contentCountPubmed = countPubmed.totalArticleRecords;
alert(contentCountPubmed); //return 15 for example
};
var handleFailure = function () {
alert("Error connecting data : Bad pubmed query");
};
var callback =
{
success:handleSuccess,
failure:handleFailure,
timeout: 5000
};
var sURL = 'qct-list-article.html?term=' + contentCurValue + '&retstart=0' + '&retmax=1';
var request = YAHOO.util.Connect.asyncRequest('GET',sURL,callback);
}
I would like this function return : "contentCurValue" (eg:15), but when I try to use this code I get "undefined" :
var test = getCountArticle();
alert(test); // return undefined, should return 15
My error is probably due to asynchronous query, but how can I force "var test = getCountArticle();" to wait for results ?
Since the call is by nature asynchronous, rather than try to wait for the response, you would be better off specifying a callback function to execute with the data. You could modify your method like this:
function getCountArticle(contentCurValue, callback) {
var handleSuccess = function (res) {
var countPubmed = YAHOO.lang.JSON.parse(res.responseText);
var contentCountPubmed = countPubmed.totalArticleRecords;
callback(contentCountPubmed); //return 15 for example
};
// ...
}
then your calling code would be:
getCountArticle("contentCurValue", function(test) {
alert(test);
});
Any further execution using the value returned from your AJAX query would proceed inside of your callback method.
This SO post is essentially the same problem, but not YUI specific: Getting undefined in javascript when calling ajax

Categories

Resources