I have the following loop which I have to make on my client API. On each iteration of loop I must add data returned from the API call as an object to an object array, then at the end of the loop I need to display the content of the object array.
Due to the nature of JS code execution (asynchronous) displaying the object array content always return undefined, so I was wondering if someone can please help me with a solution to this problem. Thanks.
var invoiceObj = {};
var invoiceObjArray = [];
for (var i=0; i< 5; i++)
{
//getAllInvoices returns a promise from $http.GET calls...
ClientInvoiceService.getAllInvoices(i).then(function(invoice){
invoiceObj = { invoiceNum: invoice.Result[0].id,
clientName: invoice.Result[0].clientName};
invoiceObjArray.push(invoiceObj);
}, function(status){
console.log(status);
});
}
console.log(invoiceObjArray[0]); //return undefined
console.log(invoiceObjArray[1]); //return undefined
What you'll need to do is store all promises and then pass these to $q.all (scroll all the way down), which will wrap them in one big promise that will only be resolved if all are resolved.
Update your code to:
var invoiceObj = {};
var invoiceObjArray = [];
var promises = [];
for (var i=0; i< 5; i++)
{
//getAllInvoices returns a promise...
promises.push(ClientInvoiceService.getAllInvoices(i).then(function(invoice){
invoiceObj = { invoiceNum: invoice.Result[0].id,
clientName: invoice.Result[0].clientName};
invoiceObjArray.push(invoiceObj);
}, function(status){
console.log(status);
}));
}
$q.all(promises).then(function(){
console.log(invoiceObjArray[0]);
});
This Egghead video is a nice tutorial to using $q.all:
Related
excuse me anyone can help me??
i try to get data with condition and how to get data if value not same after condition, and this is my data.
car
[
0:{
id: 1,
subcar:[
0:{id_car:1},
1:{id_car:2}
]
}];
owner
[
0:{
id:1,
id_car:1
},
1:{
id:2,
id_car:2
},
2:{
id:3,
id_car:3
}];
and down here is condition code UPDATE
example
`app.controller('MainCtrl', function ($scope, $http){
function cars(){
$http.get('api/car').then(function(car){
for(var i = 0; i < car.length; i++)
{
var car1 = car[i].subcar;
for (var j=0; j< car1.length; j++){
$scope.car2 = car1[j].id_car;
}
}
});
}; cars();
function owners(){
$http.get('api/owner').then(function(owner){
for(var i = 0; i < owner.length; i++)
{
var owner1 = owner[i].id_car;
if (owner1 === $scope.car2){
//theen he must get data id_car:3 not exist????
}
}
});
};owners();
});
so how to get data id_car:3 after condition in function owners??
thanks
You are making 2 ajax calls, where the callback of the second call relies on data from the first call.
AJAX calls are asynchronous, meaning they run in the background while your code continues to execute. The owners call happens straight after the cars call, while the cars request is still running. It's mostly unpredictable which call will return first.
You need to change your logic to execute your ajax calls in a promise chain, and then do your processing after wards.
function getCarsData() {
return $http.get('api/car'); // this returns a promise, resolved when the ajax call returns
}
function getOwnersData() {
return $http.get('api/owners');
}
$q.all([getCarsData(), getOwnersData()]).then(function (results) {
var car_data = results[0];
var owner_data = results[1];
// you can do your logic here
});
$q.all takes an array of promises (returned from the ajax calls), and returns a promise that resolves when all of the promises are resolved, passing the resolve values as an array to the then callback.
You probably want to do some error checking, etc. as well.
I have an array of Facebook groupIDs that I want to check in synchronous order, and if one fails, to skip to the next. When they all finish executing, I want to send all the results to my server.
The below code explains the gist of what I want to accomplish (of course it does not work):
var groups = [1111,2222,3333];
var feed_collection = [];
// Unfortunately this for loop does not wait for the FB api calls to finish before looping to next
for(var x = 0; x < groups.length; x++){
FB.api("/"+groups[x]+"/feed", function(response, err){
feed_collection += response;
});
}
// Send the feed_collection to server
feed_collection.sendToServer();
How can I get my for loop to wait? I know I can use $q.all(), however I am stuck on how to generate the promises and save them to a promise_array. This code is on the client-side and I am using AngularJS 1, but I am open to any approach. Mucho gracias!
function getGroupFeed(groupId) {
var deferred = $q.defer();
FB.api('/' + groupId + '/feed', function (response, err) {
if (err) return deferred.reject(err);
return deferred.resolve(response);
});
return deferred.promise;
}
That is how you can quickly generate a promise in Angular. Now you can also create an array of promises:
var groupPromises = groups.map(function (groupId) {
return getGroupFeed(groupId);
});
Or if you insist on a for loop:
var groupPromises = [];
for (var i = 0, len = groups.length; i < len; i++) {
groupPromises.push(getGroupFeed(group[i]));
}
This array of promises can then be used in $q.all, which is only resolved once all promises in the array are resolved.
I've got an array of names which I need to retrieve data from, and I'm currently doing this with $.getJSON inside a loop. It works and I can retrieve the data, but to output the correct value I need to use setTimeout or similar. I'm wondering if there's a more refined way of doing what I'm looking to achieve.
Here's what I've got.
var names = ["riotgames", "example"];
var online = [];
for (var i = 0; i < names.length; i++) {
$.getJSON('https://api.twitch.tv/kraken/streams/' + names[i], function(data) {
if (data.stream != null) {
online.push(data.stream.channel.display_name);
};
});
}
console.log(online) // outputs []
setTimeout(function() {
console.log(online) // outputs correctly
}, 1000);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
When doing $.getJSON, you are triggering asynchronous requests. This means they run in the background. You do not wait for them to finish, their callbacks will trigger (like an event) once the request is done.
This means you cannot access online from outside the callback(s).
If you want to "wait" for all the requests to finish, then I suggest using promises. You can use $.when to combine all the requests into one promise then run a callback once everything is done.
var names = ["riotgames", "example"];
var promises = [];
for (var i = 0; i < names.length; i++) {
// $.getJSON returns a promise
promises.push($.getJSON('https://api.twitch.tv/kraken/streams/' + names[i]));
}
// Combine all promises
// and run a callback
$.when.apply($, promises).then(function(){
var online = [];
// This callback will be passed the result of each AJAX call as a parameter
for(var i = 0; i < arguments.length; i++){
// arguments[i][0] is needed because each argument
// is an array of 3 elements.
// The data, the status, and the jqXHR object
online.push(arguments[i][0].stream.channel.display_name);
}
console.log(online);
});
I've searched high and low but I just can't seem to wrap my head around q.defer() and creating my own promise.
I have a service getDataService which does exactly that - $http.gets data from a REST server. However only one of each variable can be sent at a time, so if user wants to query server for two entities and return the entire associated data they must send two requests. Because of this I had to use a method which kept i as the actual count (closure) which then runs my get data function the appropriate amount of times:
keepICorrect: function (security) {
var self = this;
for (var i = 0 ; i < entity.length; i++) {
self.getDataFromREST(security, i);
}
},
I call this from my main controller as a promise :
$scope.apply = function (security) {
var myDataPromise = getDataService.keepICorrect(security);
myDataPromise.then(function () {
//DO STUFF
}, 1);
}, function (error) {
alert("Error Retrieving Data");
return $q.reject(error);
});
}
This worked when using .getDataFromREST() but obviously doesn't now as I have to route through my new loop function, keepICorrect().
My question is how on earth do I create a promise which spans from my service to my controller, but not only that, also waits to resolve or fail depending on whether the i amount of requests have completed?
You need to create an array of promises
keepICorrect: function (security) {
var self = this;
var promises = [];
for (var i = 0 ; i < entity.length; i++) {
promises.push(self.getDataFromREST(security, i));
}
return promises;
},
And then wait for all of them to complete using the $q library in Angular
$q.all(getDataService.keepICorrect(security))
.then(....
I have a page than can make a different number of $http requests depending on the length of a variables, and then I want to send the data to the scope only when all the requests are finished. For this project I do not want to use jQuery, so please do not include jQuery in your answer. At the moment, the data is sent to the scope as each of the requests finish, which isn't what I want to happen.
Here is part of the code I have so far.
for (var a = 0; a < subs.length; a++) {
$http.get(url).success(function (data) {
for (var i = 0; i < data.children.length; i++) {
rData[data.children.name] = data.children.age;
}
});
}
Here is the part that I am sceptical about, because something needs to be an argument for $q.all(), but it is not mentioned on the docs for Angular and I am unsure what it is meant to be.
$q.all().then(function () {
$scope.rData = rData;
});
Thanks for any help.
$http call always returns a promise which can be used with $q.all function.
var one = $http.get(...);
var two = $http.get(...);
$q.all([one, two]).then(...);
You can find more details about this behaviour in the documentation:
all(promises)
promises - An array or hash of promises.
In your case you need to create an array and push all the calls into it in the loop. This way, you can use $q.all(…) on your array the same way as in the example above:
var arr = [];
for (var a = 0; a < subs.length; ++a) {
arr.push($http.get(url));
}
$q.all(arr).then(function (ret) {
// ret[0] contains the response of the first call
// ret[1] contains the second response
// etc.
});