I’m using the Facebook graph API to get a user’s friend list and generate a status message based on a template and random friends. If I use alert(response.data[0].name); instead of return(response); my code works and I see the name of the first Facebook friend. When I take it further in my code, it throws an error as undefined. Based on a few hours of trying to work out the problem, I’m thinking I have some kind of issue with scope that doesn’t allow me to use the response any longer or a problem with JSON formatting. I tried playing around with jQuery’s JSON parse as well but didn’t gain anything additional there.
shuffle = function(v){
for(var j, x, i = v.length; i; j = parseInt(Math.random() * i), x = v[--i], v[i] = v[j], v[j] = x);
return v;
};
function getFriends() {
FB.login(function(response) {
if (response.session && response.perms) {
FB.api('/me/friends', function(response) {
return response;
});
}
} , {perms:'publish_stream'});
};
function selectFriend(){
var friends = getFriends();
friends = friends.data[0];
var findex = friends.length
var randomNumber = (Math.floor( Math.random() * 10 ) % findex);
return(friends[randomNumber].name);
};
function process(status){
status = status[0].toString();
var cindex = status.indexOf("{{friend}}");
while (cindex != -1){
status = status.replace("{{friend}}",selectFriend());
cindex = status.indexOf("{{friend}}");
}
return(status);
};
function newStatus(){
var status = [
"This status is named {{friend}}",
"This status loves {{friend}} but likes {{friend}} too.",
"This status goes by {{friend}} but you can call it {{friend}} if you like.",
"This status hates {{friend}}"
];
status = shuffle(status);
$('#status').text(process(status));
}
The code begins with calling newStatus() on click.
EDIT: Here’s how I refactored my code to work after jfriend00’s answer:
shuffle = function(v){
for(var j, x, i = v.length; i; j = parseInt(Math.random() * i), x = v[--i], v[i] = v[j], v[j] = x);
return v;
};
function newStatus(){
var status = [
"This status is named {{friend}}",
"This status loves {{friend}} but likes {{friend}} too.",
"This status goes by {{friend}} but you can call it {{friend}} if you like.",
"This status hates {{friend}}"
];
status = shuffle(status);
status = status[0].toString();
FB.login(function(response) {
if (response.session && response.perms) {
FB.api('/me/friends', function(response) {
var friends = response.data;
var findex = friends.length
var cindex = status.indexOf("{{friend}}");
while (cindex != -1){
var randomNumber = (Math.floor( Math.random() * 10 ) % findex);
var name = friends[randomNumber].name;
status = status.replace("{{friend}}",name);
cindex = status.indexOf("{{friend}}");
}
$('#status').text(status);
});
}
} , {perms:'publish_stream'});
}
The issue is probably that the calls to the FB api are asychronous. That means when you call FB.api(), it starts an ajax call to FB. Your other code continues to run while that ajax call is being completed. In fact, your call to getFriends finishes and the rest of selectFriend() runs too before the FB ajax call has completed.
Then, when the FB api call does complete, it calls the completion function (probably where you put an alert). In your code, you aren’t doing anything meaningful in the completion function. You’re just returning the response with
But, that isn’t doing anything useful. That return value is not a return from the getFriends() function. It’s a return back to something inside the ajax engine.
If you want to do something useful with the
FB.api() response, you need to run that code or call that code from the completion function specified in theFB.api()call.You would have to do something like this pseudo code: