I'm new to AngularJS, and is experimenting AngularJS with Twitch API.
I have a list of channels that I'm interested in, defined as var channels.
Then I use the $http.get function to loop through another array, twitchList.channels, which contains the API addresses that I'm supposed to call.
(function() {
var app = angular.module('twitchList', []);
app.controller('twitchController', ['$http', function($http){
var twitchList = this;
twitchList.channels = [];
var channels = ["freecodecamp", "storbeck", "terakilobyte", "habathcx","RobotCaleb","thomasballinger","noobs2ninjas","beohoff", "MedryBW"];
for (var i = 0; i < channels.length; i++ ) {
twitchList.channels.push({
name: channels[i],
api: 'https://api.twitch.tv/kraken/streams/' + channels[i],
})
}
var data_list = [];
for (var j = 0; j < twitchList.channels.length; j++) {
$http.get(twitchList.channels[j].api).success(function(data){
data_list.push(data);
})
}
// Issue arises here!
console.log(data_list);
console.log(data_list.length);
}]);
})();
The API calls seems to be working perfectly, however, I need to get the results of the API call into an array, called data_list. Now, when I print data_list, and data_list.length, what happens is that data_list.length always returns 0, and data_list is sometimes populated (meaning it's either 0 size array or 9 size array). Even though the property of the array has a length 9, but calling .length always gives 0.
This let me think that the controller code is not executed line by line? Or is there something wrong with my logic?
Can someone give me a pointer? Thanks
No, this line:
data_list.push(data);
will be executed when you receive a response on the http request sent a line above. Hence the following lines:
console.log(data_list);
console.log(data_list.length);
will output [] and 0
I've not used it before, but could you possibly use $q.all in order to resolve multiple promises? I've used the equivalent $.when function in jQuery to achieve this in the past.
var data_list = [];
var promise_array = [];
var request;
for (var j = 0; j < twitchList.channels.length; j++) {
request = $http.get(twitchList.channels[j].api);
request.success(function(data) {
data_list.push(data);
});
promise_array.push(request);
}
$q.all(promise_array).then( function() {
console.log(data_list);
console.log(data_list.length);
});
Related
I have an angular factory with a function that loads a range of items from a list via an API. So if I wanted to load the first 10 I would say something like getRange(0, 10). Once the JSON returns from the API, I copy the items over to a local model using angular.copy... But how do I load the next 10 and copy the list items over, without deleting the old ones. Apparently, I can't continue to use angular.copy because it deletes the old items and then copies over the new items.
Any guidance?
You can think something like this:
var app = angular.module('plunker', []);
app.controller('demoController', function($scope) {
$scope.arr = []; // data from factory.
for (var i = 0; i < 100; i++) { // for demo filling it up
$scope.arr.push({ item: i }); // just like this
}
$scope.newArr = []; // the new item array;
$scope.len = $scope.newArr.length || 10;
$scope.getItems = getItems;
function getItems() {
for (var i = $scope.len - 10; i < $scope.len; i++) {
$scope.newArr.push(angular.copy($scope.arr[i]))
}
$scope.len += 10;
}
});
Take a look at the plnkr here.
I am new to angular and been struggling how to solve my problem.
I need to access API multiple times for users data, store everything as JSON array and when all the data is collected(all results as one array) it needs to be passed to directive which will use it to draw visualization(eg. d3.js-pie chart).
$scope.allData = [];
$http.get("****link here****/students")
.success(function (data) {
students = data;
for (i = 0; i < students.length; i = i + 1) {
$http.get("**** link here ****/quest/" + students[i].id)
.success(function (data) {
quest = data;
$scope.allData.push({
id: quest.id,
value: quest.length
});
}
}
and then pass it to directive as
<bar-chart data='allData'></bar-chart>
even if I set watch in directive and have scope as '=' the directive gets empty array.
In my other code when I just do one http get call for json array I can pass it to directive easily and it works fine.
EDIT1:
OK so I use premises now, but still allData array is 0.
Even with simple example like this:
$scope.allData = [];
var promieses = [];
for (i = 0; i < 10; i = i + 1) {
promieses.push($http.get("***link***/student/" + students[i].id));
}
$q.all(promieses).then(function (data) {
for (i = 0; i < data.length; i = i + 1) {
$scope.allData.push("test");
}
});
in html {{ allData ]] // 0
This is a great place to unleash the power of $q. You can wait for all the promises to resolve and then process them using $q.all method. It simply Combines multiple promises into a single promise that is resolved when all of the input promises are resolved.
See this example:
students = data;
var promises = [];
for (i = 0; i < students.length; i = i + 1) {
promises.push($http.get("**** link here ****/quest/" + students[i].id));
}
$q.all(promises).then(function(response) {
for (var i = 0; i < response.length; i++) {
$scope.allData.push({
id: response[i].data.id,
value: response[i].data.length
});
}
})
See it in action here: http://plnkr.co/edit/TF2pAnIkWquX1Y4aHExG?p=preview
I have this code:
rtclient.listFiles = function(callback) {
gapi.client.load('drive', 'v2', function() {
gapi.client.drive.files.list({
'maxResults': 20
}).execute(callback);
});
}
which I try to assign to an array using this code:
var arrayStore;
rtclient.listFiles(function(x) {
for(var i in x.items) {
arrayStore.push(x.items[i].id);
}})
However, the array arrayStore is not storing anything. This is using the Google Drive API and I am trying to access some file IDs to iterate over. Can anyone help?
the point is you should have a error like:
TypeError: Cannot call method 'push' of undefined
because you haven't defined it as an array, the other point is don't use for(...in) for arrays, you can find reasons about that in this post:
Why is using “for…in” with array iteration such a bad idea?
var arrayStore = [];
rtclient.listFiles(function(x) {
for(var i = 0; i < x.items.length; i++) {
arrayStore.push(x.items[i].id);
}
});
The other important point as #toothbrush has commented is, since the Google Drive API is asynchronous, you can't access the contents of arrayStore immediately, in other word to continue your scenario you should do something like this:
var arrayStore = [];
rtclient.listFiles(function(x) {
for(var i = 0; i < x.items.length; i++) {
arrayStore.push(x.items[i].id);
}
nextStep();
});
function nextStep(){
//here you would have access to arrayStore
console.log(arrayStore);
}
In my project I am calling same service for more than 2-3 times for finding distance & time for my route in javascript using cloudmode service.
I am having one polyline, I am getting each point of polyline & passing two consecutive points to service to get response from it.
What I am doing is
function showPointsRoutes(e)
{
var a = e.target.getLatLngs();
for(var i = 1 ; i < a.length ; i++)
{
var as ="http://routes.cloudmade.com/BC9A493B41014CAABB98F0471D759707/api/0.3/" + a[i-1].lat+","+a[i-1].lng+","+a[i].lat+","+a[i].lng + "/car/shortest.js?callback=getRouteResponse";
addScript(as);
}
}
function getRouteResponse(response)
{
mytimeArray.push[response.route_summary.total_time];
myDistancArray.push[response.route_summary.total_distance];
}
function addScript(url)
{
var script = document.createElement('script');
script.type="text/javascript";
script.src=url;
document.getElementsByTagName('head') [0].appendChild(script);
}
But sometimes what happens is that response for some requests comes late.
due to this I am not getting proper times & distance between points.
Can any one suggest some way so that I get values in array as sequence in which request was made.
The reason they give you different callback names is so that you can differentiate requests by using a different callback for each one. Try something like this:
Note: #Rodrigo Assis's suggestion would be better in this case since the API supports this. Code below demonstrates a way to handle this when the API forces using multiple requests.
function showPointsRoutes(e)
{
var a = e.target.getLatLngs();
for(var i = 1 ; i < a.length ; i++)
requestRoute(i, a[i-1], a[i]);
}
function requestRoute(i, a, b)
{
window["getRouteResponse" + i] = function(response)
{
mytimeArray[i] = response.route_summary.total_time;
myDistancArray[i] = response.route_summary.total_distance;
};
var as ="http://routes.cloudmade.com/BC9A493B41014CAABB98F0471D759707/api/0.3/" + a.lat+","+a.lng+","+b.lat+","+b.lng + "/car/shortest.js?callback=getRouteResponse" + i;
addScript(as);
}
function addScript(url)
{
var script = document.createElement('script');
script.type="text/javascript";
script.src=url;
document.getElementsByTagName('head') [0].appendChild(script);
}
Using javascript I get list of facebook friends though it only returns name and id now, but I need to get the picture of each user. I try to loop through the response and then try to call the api to get picture, but due to it's async call I can't associate the returned picture with the index of the friend in the array. *this is kinda a problem that I've had with asynchronous programming in general, is there a standard pattern for this?
Example.
FB.api('me/friends', function(response) {
if(response.error == null){
var friendsSale = response.data;
var len = friendsSale.length;
for(var x=0; x<len; x++){
FB.api(friendsSale[x].id+'/picture', function(response) {
//x no longer is the same x as the initial call, and I can't pass in the orignal array object into the FB.api function to return as part of the response... or can I?
friendsSale[x].pictureUrl = response;
});
}
}
//Then how do I know when I have all the pictures set so I can then set datamodle with the complete friend array?
m.friends(friendsSale);
}
});
Yes, there is a pattern for this: a Closure
...
var len = friendsSale.length;
for (var i = 0; i < len; i++) {
(function() {
var j = i;
FB.api(friendsSale[i].id+'/picture', function(response) {
friendsSale[j].pictureUrl = response;
});
})();
}
To know when all all calls have returned you can simply keep a counter of returned calls, e.g.
...
var len = friendsSale.length;
var returnedCallsCounter = 0;
for (var i = 0; i < len; i++) {
(function() {
var j = i;
FB.api(friendsSale[i].id+'/picture', function(response) {
friendsSale[j].pictureUrl = response;
// Track number of returned calls
returnedCallsCounter++;
// Check if all calls have returned
if (returnedCallsCounter == len) {
m.friends(friendsSale);
}
});
})();
}
Simple solution for you :
All you have to do is query this :
https://graph.facebook.com/user_id/picture
and you will get the users profile picture. For example :
Querying https://graph.facebook.com/4/picture (with no access token BTW - try it in chrome pron incognito mode) :
<img src="https://graph.facebook.com/4/picture">
will yeild this smiling face :
Now you know Marks fbid :P