Javascript "push" into array not working (Facebook app) - javascript

I am trying to store my friends list (name, picture and gender) on a var, but it doesn't work correctly. Please ready the comments in the code for the details. Any ideas? Thanks.
function getFriendsArray() {
var friendsArray = [];
FB.api('/me/friends?fields=name,picture,gender', function(response) {
if(response.data) {
var data = '';
$.each(response.data, function(indice, item) {
alert(item.name); // Friend's name are displayed correctly
friendsArray.push(item); // I believe this doesn't work
});
}
else {
errorHandler('getFriendsArray', JSON.stringify(response));
}
});
alert(friendsArray.length); // Returns 0 (incorrect)
return friendsArray.sort(sortByName);
}

The call function(response) is asynchronous. You should insert the alert after $.each
for completeness: you should change your approach to problem: do not call a function that returns an Array but that call a second function.
function getFriendsArray(callback, errorHandler) {
var friendsArray = [];
FB.api('/me/friends?fields=name,picture,gender', function(response) {
if(response.data) {
var data = '';
$.each(response.data, function(indice, item) {
alert(item.name); // Friend's name are displayed correctly
friendsArray.push(item); // I believe this doesn't work
});
callback(friendsArray);
}
else {
errorHandler('getFriendsArray', JSON.stringify(response));
}
});
}
getFriendsArray(function(friends) {
alert(friends);
},
function(error) {
alert('error');
});

It looks like the FB.api makes an asynchronous request (like jQuery.ajax) and so you are executing alert(friendsArray.length) before the FB.api call completes and pushes the results into the friends array.

Related

Symfony : Add data from Ajax call to js array

I have an Ajax request that fetch data in database.
These data may vary in function of the action that calls the ajax request.
Each time the Ajax request is called, I want some ot these datas to be pushed in a javascript array declared outside of the Ajax function.
The problem is, each time Ajax is called, my function manage to put the wanted data in the array but erases the previous data.
Here is the script :
<script>
let myArray = [];
function fetchWeeksForViewportWidth(startDate) {
//AJAX
$.ajax({
method: "GET",
url: "{{path('days_json')}}",
data: {
//some data
},
success: function (data) {
let trParents = document.getElementsByClassName('project-assignment');
$.each(trParents, function(key, parent) {
let assId = parent.dataset.assignmentId;
myArray[assId] = [];
$.each(data['days'], function(key, value) {
myArray[assId][value.code] = 0;
//some other treatment
if(value.code in data['game']) {
myArray[assId][value.code] = data['game'][value.code];
});
});
});
},
error: function() {
//handle error
console.log("error")
}
});
}
$(document).ready( function () {
function displayArray(){
console.log(myArray);
setTimeout(displayArray, 5000);
}
displayArray();
});
</script>
Any idea why new data don't add to the ones from previous ajax calls but keep replacing them ?
Instead of assignment
myArray[assId][value.code] = 0;
try the push() function of the array
myArray[assId].push(0);
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/push

Backbone - Can't get attributes

I have a function which does a fetch, it returns successful and sets the data.
But I can't work out how to get the data out of the model again.
fetchAcceptedTerms: function () {
var self = this;
this.appAcceptedTerms = new T1AppAcceptedTerms();
this.acceptedTerms = new AppAcceptedTerms();
this.acceptedTerms.fetch({
success: function (data) {
console.log(data);
if (data.meta.status === 'success') {
self.appAcceptedTerms.set(data.data);
}
}
});
console.log(self.appAcceptedTerms);
console.log(self.appAcceptedTerms.attributes);
},
See output in console:
http://s32.postimg.org/ssi3w7wed/Screen_Shot_2016_05_20_at_14_17_21.png
As you can see:
console.log(data); returns the data as expected
console.log(self.appAcceptedTerms); the data is set correctly as we can see it in the log
console.log(self.appAcceptedTerms.attributes); isn't working properly and returns Object {}
Can someone help on how to get all of the attributes out?
Thanks
The fetch operation is asynchronous, so you need to check for your attributes after the fetch operation has completed. Does the below output your attributes as expected?
fetchAcceptedTerms: function () {
var self = this;
this.appAcceptedTerms = new T1AppAcceptedTerms();
this.acceptedTerms = new AppAcceptedTerms();
this.acceptedTerms.fetch({
success: function (data) {
console.log(data);
if (data.meta.status === 'success') {
self.appAcceptedTerms.set(data.data);
console.log(self.appAcceptedTerms);
console.log(self.appAcceptedTerms.attributes);
}
}
});
}

How to pull JSON data from two different sources?

I was wondering if there is a way to pull and use JSON data from two different sources. Currently, the code looks like this:
//JSON1
$.getJSON('url1',function(data){
$.each(data,function(key,val){
//code
});
});
//JSON2
$.getJSON('url2',function(data){
$.each(data,function(key,val){
//code
});
});
When I do this, i seems that variables created from one JSON function aren't available in the other one, which makes it hard for them to be useful together.
Is there a better way to have these two work together?
This function takes an array of urls and a callback as parameters:
function getMultiJSON(urlList,callback) {
var respList = {};
var doneCount = 0;
for(var x = 0; x < urlList.length; x++) {
(function(url){
$.getJSON(url,function(data){
respList[url] = data;
doneCount++;
if(doneCount === urlList.length) {
callback(respList);
}
});
})(urlList[x]);
}
}
You would use it like this:
getMultiJSON(['url1','url2'],function(response) {
// in this case response would have 2 properties,
//
// response.url1 data for url1
// response.url2 data for url2
// continue logic here
});
You might want to add a timeout as the function will never call your handler should any of the URLs fail to load
Variable declared within the functions using var (or blocks, using let) are not available outside of the functions (or blocks).
$.getJSON('url1',function(data){
$.each(data,function(key,val){
var only_accessible_here = key;
});
});
So if you want variables that are accessible outside the scope of the function they are declared in, you need to declare them outside of the function they are used in.
var combined_stuff = ''
$.getJSON('url1',function(data){
$.each(data,function(key,val){
combined_stuff += val;
});
});
//JSON2
$.getJSON('url2',function(data){
$.each(data,function(key,val){
combined_stuff += val;
});
});
As Marc B says, there is no way to know which order the combined_stuff variable will be updated, either by JSON1 first, or by JSON2 first, or by only one, if one of the getJSON calls fail, or by neither if both fail.
If the order of updating is important, call the one you want to use second in the function of the one you want to call first.
var combined_stuff = ''
$.getJSON('url1',function(data){
$.each(data,function(key,val){
combined_stuff += val;
//JSON2
$.getJSON('url2',function(data){
$.each(data,function(key,val){
combined_stuff += val;
});
});
});
});
Easily using the open source project jinqJs (http://www.jinqJs.com)
var data1 = jinqJs().from('http://....').select();
var data2 = jinqJs().from('http://....').select();
var result = jinqJs().from(data1, data2).select();
The example does a sync call, you can do an async call by doing something like this:
var data1 = null;
jinqJs().from('http://....', function(self){ data1 = self.select(); });
Result will contain both results combined.
If you control the endpoint, you could make it return all of the data you want in one shot. Then your data would look like:
{
"url1_data": url1_json_data,
"url2_data": url2_json_data
}
If you still have 2 endpoints you need to hit, you can pass the result of your first ajax call to the second function (but this makes your 2 ajax calls synchronous):
function getJson1(){
$.getJSON('url1',function(data){
getJson2(data);
});
}
function getJson2(json1Data){
$.getJSON('url2',function(data){
//Do stuff with json1 and json2 data
});
}
getJson1();
I would recommend you to use $.when function available in jquery to execute both the methods in parallel and then take the action. See the code snipped below,
var json1 = [], json2 = [];
$.when(GetJson1(), GetJson2()).always(function () {
//this code will execute only after getjson1 and getjson2 methods are run executed
if (json1.length > 0)
{
$.each(json1,function(key,val){
//code
});
}
if (json2.length > 0)
{
$.each(json2,function(key,val){
//code
});
}
});
function GetJson1()
{
return $.ajax({
url: 'url1',
type: 'GET',
dataType: 'json',
success: function (data, textStatus, xhr) {
if (data != null) {
json1 = data;
}
},
error: function (xhr, textStatus, errorThrown) {
json1 = [];//just initialize to avoid js error
}
}
function GetJson2()
{
return $.ajax({
url: 'url2',
type: 'GET',
dataType: 'json',
success: function (data, textStatus, xhr) {
if (data != null) {
json2 = data;
}
},
error: function (xhr, textStatus, errorThrown) {
json2 = [];//just initialize to avoid js error
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
The returned data from each AJAX call are not available outside its own callback function. I'm sure there are more elegant (complex?) solutions, but a couple of simple, Occamic, solutions include global variables, or storing the received data in hidden input elements.
Within each callback function, just loop until the data from the other call is present:
function getJson1(){
$.getJSON('url1',function(data){
var d2 = '';
$('#hidden1').val(data);
while ( d2 == '' ){
//you should use a time delay here
d2 = $('#hidden2').val();
}
getJson2();
});
}
function getJson2(){
$.getJSON('url2',function(d2){
var d1 = '';
$('#hidden2').val(d2);
while ( d1 == '' ){
//you should use a time delay here
d1 = $('#hidden1').val();
}
//Do stuff with json1 and json2 data
});
}
getJson1();

javascript callback function call itself until true

I am running a function that i need to keep running until i get a response example
exports.getJson = function(url, callback) {
var loader = Titanium.Network.createHTTPClient();
loader.open("GET", url);
loader.onload = function() {
var response = JSON.parse(this.responseText);
callback(response);
};
loader.onerror = function(e) {
callback(false);
};
// Send the HTTP request
loader.send();
}
ok the problem i am having is it will sometimes give me a response of null and i need it to run again.
so i am calling it like this.
url = 'http://example.com/test.json';
main.getJson(url, function(response) {
if(response){
addData(response);
}else{
//return no response i need to run the function again now until it comes back as true
}
});
Can anyone give me a good way to do this maybe try at least 3 times then return false???
Thanks
Just put the code in function and call it again:
var counter = 0;
function getData() {
main.getJson('http://example.com/test.json', function(response) {
if(response){
addData(response);
}
else if (counter < 3) {
counter++;
getData();
}
});
});

Javascript\Kango: How to get a return of an async JS function inside a non-async function?

My theory might be a bit weak asking this, so feel free to let me know.
This code is part of a browser plugin using Kango framework. Basically I have code that generates a random string that's a userID. I also have another function that sets up a big ole JSON. It looks something like this:
function createJSON() {
data = {};
data["userID"] = generateID();
}
function generateID() {
kango.invokeAsync('kango.storage.getItem', 'userID', function(data) {
uid = data;
if (!uid) {
console.log("uid doesn't exist, creating uid!");
kango.invokeAsync('kango.storage.setItem', userID, function(data) { return data; });
} else {
console.log("uid found!: " + uid);
return uid;
}
return data;
});
}
kango.invokeAsync docs are here. My understanding is it works a bit like an async ajax call and in that sense it doesn't return just in time for when I'm trying to assign its value to data["userID"].
I think I can solve this by doing doing the userID call first and then using it's callback(a bit vague on the terminology here) to go ahead and add to the data array.
I have no clue if that's the right way to do it though. How do I get a return of an async function to work with?
Take a look more closer to invokeAsync examples from documentation.
In your code you have two mistakes with invokeAsync and kango.storage.setItem call:
// 1. Second argument should be string 'item name'
// 2. Third argument should be 'item value'
kango.invokeAsync('kango.storage.setItem', userID, function(data) { callback(data); });
You should use kango.storage.setItem with invokeAsync in this way:
kango.invokeAsync('kango.storage.setItem', 'userID', '123');
So, result code will be like this:
function generateID(callback) {
kango.invokeAsync('kango.storage.getItem', 'userID', function(uid) {
if(!uid) {
kango.console.log("uid doesn't exist, creating uid!");
uid = '123'; // TODO: replace with your ID generation algorithm
kango.invokeAsync('kango.storage.setItem', 'userID', uid);
}
else {
kango.console.log("uid found!: " + uid);
}
callback(uid);
});
}
data = {};
generateID(function(uid) {
data["userID"] = uid;
});
You can't do it like this because of the async nature of generateID(). It will return BEFORE the async call has finished, thus the data is not available:
data["userID"] = generateID();
Instead, you have to use a callback like this:
generateID(function(val) {data["userID"] = val;});
function generateID(callback) {
kango.invokeAsync('kango.storage.getItem', 'userID', function(data) {
uid = data;
if (!uid) {
console.log("uid doesn't exist, creating uid!");
kango.invokeAsync('kango.storage.setItem', userID, function(data) { callback(data); });
} else {
console.log("uid found!: " + uid);
callback(uid);
}
});
}
When using asynchronous functions, you CANNOT use normal sequential programming. Instead, you have to continue your execution flow in the completion callback because ONLY then is the result of the async function known.
Thus, you won't be able to call createJSON() and return the desired value from that. If any code after createJSON() needs the results, it also has to be in a callback.
function createJSON() {
data = {};
generateID(function(id) {
data["userID"] = id;
});
}
function generateID(callback) {
kango.invokeAsync('kango.storage.getItem', 'userID', function(data) {
uid = data;
if (!uid) {
console.log("uid doesn't exist, creating uid!");
kango.invokeAsync('kango.storage.setItem', userID, function(data) { callback(data); });
} else {
console.log("uid found!: " + uid);
callback(uid);
}
callback(data);
});
}
Would this work for you?
You can't return an object from an async call. Rather create another function and pass the callback object to it.
// some code
if (!uid) {
console.log("uid doesn't exist, creating uid!");
kango.invokeAsync('kango.storage.setItem', userID, function(data) {
getData(data);
});
} else {
console.log("uid found!: " + uid);
getData(uid);
}
function getData(data) {
// Use data here.
}

Categories