$http in loop, wait the results - angularjs

I have this :
var j = 0;
// myList.length = 3
while(j < self.myList.length - 1){
$http.post('myURL', self.myList[j].code).then(
function(response){
self.myList[j].plop = response.data;
}, function(){
// error
}
).then(
function(){
// with this j++, my web page is freezing
// j++;
}
);
// with this j++, only the 3rd element of myList have a "plop" element
//j++;
}
My problem is in comments :) for "j++".
If I remove the loop while and hardcoded the 3 step, it's working. But I don't know how to solve the issue with a loop. Do you have an idea ? Thanks

Synchronized solution according to OP's comment:
var promises = [];
for(var i=0;i<self.myList.length;i++)
promises.push($http.post(...));
$q.all(promises).then(function(results){
//All results available here
var data = results.map(result => result.data);
data.forEach((e, idx) => self.myList[idx] = e);
})
.catch(function(e){
//Handle error
});

Issue is
$http.post().then(function(){}, function(){}) is asynchronous function. So .then() method will be executed when loop is completed. This is the reason it always takes last value of j that is 2.
then() will come only one time with $http.post() so remove second .then()
Solution posted below:
var j = 0;
var i = 0;
// myList.length = 3
while(j < self.myList.length - 1){
$http.post('myURL', self.myList[j].code).then(function(response){
self.myList[i].plop = response.data;
i++;
}, function(){
// error
}
);
}

Related

Using nested $http.get calls in Angular JS sequentially

I have this situation where two $http.get calls are nested.I get result from the first call and then iterating over this first result and passing this to another $http.get call and in the end I amtrying to make whole thing as ab array of objects.I am finding that ,this whole is not happening in sequence.Could someone help me out?
$scope.populateData = function()
{
$scope.infoWithStatus = [];
$http.get("commonAppGet.jsp?sqlStr=select name from test where title_id=1").then(function(resp){
$scope.names = resp.data.d;
for(var i=0;$scope.names.length;i++){
infoObject= {};
var c1=0;c2=0; c3=0;c4=0;c5=0;
$scope.spocName = $scope.names[i].name;
infoObject.name=$scope.spocName;
$http.get("commonAppGet.jsp?sqlStr=select a.status as status from test1 where name='"+$scope.spocName+"'").then(function(resp){
$scope.statusValues = resp.data.d;
for(var i=0;i<$scope.statusValues.length;i++)
{
if($scope.statusValues[i].status==0)
c1++;
if($scope.statusValues[i].status==1)
c2++;
//some code for c3,c4,c5
}
infoObject.count1=c1;
infoObject.count2=c2;
infoObject.count3=c3;
infoObject.count4=c4;
infoObject.count5=c5;
});
$scope.infoWithStatus.push(infoObject);
}
});
}
Maybe this will be you
I saw that you missing i < $scope.names.length in the first promise
$scope.populateData = function()
{
$scope.infoWithStatus = [];
var c1=0;c2=0; c3=0;c4=0;c5=0;
$http.get("commonAppGet.jsp?sqlStr=select name from test where title_id=1").then(function(resp){
$scope.names = resp.data.d;
var listPromise = [];
for(var i=0;i < $scope.names.length;i++){
infoObject= {};
$scope.spocName = $scope.names[i].name;
infoObject.name=$scope.spocName;
listPromise.push($http.get("commonAppGet.jsp?sqlStr=select a.status as status from test1 where name='"+$scope.spocName+"'"));
$scope.infoWithStatus.push(infoObject);
}
return Promise.all(listPromise);
}).then(function(resp){
for (var i = 0; i < resp.length; i++) {
$scope.statusValues = resp[i].data.d;
for(var i=0;i<$scope.statusValues.length;i++)
{
if($scope.statusValues[i].status==0)
c1++;
if($scope.statusValues[i].status==1)
c2++;
//some code for c3,c4,c5
}
infoObject.count1=c1;
infoObject.count2=c2;
infoObject.count3=c3;
infoObject.count4=c4;
infoObject.count5=c5;
}
});
}

iterating inside a $http.get

I've this block of code which displays 20 items per request.
.controller('ActorController',function($scope,$http) {
$scope.getActors = function () {
var actors = $http.get(https://api.themoviedb.org/3/person/popular&page=1);
actors.then(
function (response) {
$scope.actors = response.data.results;
}
);
}
})
Instead of page=1, if i put page=2, I'll get another set of 20 items and so on. How to iterate inside the $http.get if I want more than 1 get request in a single page? I want to display the 2nd 20 items after displaying the 1st 20.
So you're saying that you want to make multiple calls to $http.get in a loop? If so you'd do something like this:
.controller('ActorController',function($scope,$http) {
$scope.getActors = function () {
for(var i = 0; i < 5; i++) {
getPage(i);
}
}
function getPage(i) {
var actors = $http.get('https://api.themoviedb.org/3/person/popular&page=' + i);
actors.then(function (response) {
for(var j = 0; j < response.data.results.length; j++) {
$scope.actors.push(response.data.results[j]);
}
});
}
})
That will put the data for the first 5 pages into the $scope.actors array.
you can use $q.all to send multiple http requests at once
var fulAr = [];
for (var i = 1; i <= 2; i++) {
fulAr.push($http.get("https://api.themoviedb.org/3/person/popular&page=" + i))
}
$q.all(fulAr).then(function(response) {
console.log(response[0].data) //page 1 content
console.log(response[1].data) //page 2 content
for(var j = 0; j < response.length; j++) {
$scope.actors = $scope.actors.concat(response[j].data.results);
}
})
Make sure to inject $q to controller

Iterating inside $http.get

I've this block of code which displays 20 items per request.
.controller('MovieController',function ($scope,$http) {
$scope.movies = $http.get(https://api.themoviedb.org/3/movie/popular&page=1)
.then(
function (response) {
$scope.movies = response.data.results;
}
);
})
Instead of page=1, if i put page=2, I'll get another set of 20 items and so on. How to iterate inside the $http.get if I want more than 1 get request in a single page? I want to display the 2nd 20 items after displaying the 1st 20.
There is the classic way of chaining callback functions together to achieve the desired result. Or there is the better way, which uses $q.all().You should use $q.all to send multiple http requests at once
var reqAr = [];
for (var i = 0; i <= 1; i++) {
reqAr.push($http.get("https://api.themoviedb.org/3/movie/popular&page=" + i))
}
$q.all(reqAr).then(function(response) {
console.log(response[0].data) //page 1 content
console.log(response[1].data) //page 2 content
for(var j = 0; j < response.length; j++) {
$scope.movies = $scope.movies.concat(response[j].data.results);
}
})

chained promise in for loop doesn't execute properly

I have chainable promises which are working fine in a single series but now i want to call this serios of chain inside for loop but it does not work as expected.
see my demo plunker and see the output in console.
below is the structure of my chaining promises . I want all publicIP which is returned by funTwo; but I want to complete funThree() and then want to get all publicIP. As I know that $q.when() makes a value in promise object.
but you can see that console.log('pA', promiseArray); executed very before and console.log('res three'); and why successHandler and finally called before that?
Here surely I am missing something , may be have to write a return; in proper place , kindly help me how to executed all function in for loop and return a data array after that for loop ends which can be retried in successHandler
MyService.funZero()
.then(function(response) {
console.log(response);
var promiseArray = [];
for(var i = 0; i < 2 ; i++) {
console.log('I', i);
MyService.funOne()
.then(MyService.funTwo)
.then(function(res2) {
console.log('res two', res2);
publicIP = res2.ip;
console.log('i', publicIP);
promiseArray.push({'ip': publicIP});
return MyService.funThree(publicIP);
})
.then(function() {
console.log('res three');
})
} // for loop ends
console.log('pA', promiseArray);
return $q.when(promiseArray);
})
.then(function(res4){
console.log('after for loop', res4);
})
.then(successHandler)
.catch(errorHandler)
.finally(final, notify);
So, I'm not sure exactly what MyService.funThree does, but you can aggregate an array via ipArray.push({'ip': publicIP}) and return that to the MyService.funThree and then the subsequent function. The issue here is there is no guarantee of order in the ipArray if that's what you're looking for. Here's the middle section of that function:
ipArray = [];
for(var i = 0; i < 2 ; i++) {
console.log('I', i);
var promise = MyService.funOne()
.then(MyService.funTwo)
.then(function(res2) {
console.log('res two', res2);
publicIP = res2.ip;
console.log('i', publicIP);
ipArray.push({'ip': publicIP});
return ipArray;
})
.then(MyService.funThree)
.then(function() {
console.log('res three');
});
promiseArray.push(promise);
}
console.log('pA', promiseArray);
return $q.all(promiseArray);

How to Wait for Multiple ngResource $resource Queries to Resolve

I have these ngResource queries in my controller:
Ages.query(function(ages){
$scope.ages = ages;
});
Skinissues.query(function(skinissues){
$scope.skinissues = skinissues;
});
Skintypes.query(function(skintypes){
$scope.skintypes = skintypes;
});
Activities.query(function(activities){
$scope.activities = activities;
});
In the same controller in findOne function:
$scope.findOne = function() {
Products.get({
productId: $routeParams.productId
}, function(product) {
for (var i = 0; i < product.ages.length; i ++){
for (var j = 0; j < $scope.ages.length; j ++){
if (product.ages[i].id == $scope.ages[j].id){
$scope.ages[j]['ticked'] = true;
}
}
}
for (var i = 0; i < product.activities.length; i ++){
for (var j = 0; j < $scope.activities.length; j ++){
if (product.activities[i].id == $scope.activities[j].id){
$scope.activities[i]['ticked'] = true;
}
}
}
for (var i = 0; i < product.skintypes.length; i ++){
for (var j = 0; j < $scope.skintypes.length; j ++){
if (product.skintypes[i].id == $scope.skintypes[j].id){
$scope.skintypes[i]['ticked'] = true;
}
}
}
for (var i = 0; i < product.skinissues.length; i ++){
for (var j = 0; j < $scope.skinissues.length; j ++){
if (product.skinissues[i].id == $scope.skinissues[j].id){
$scope.skinissues[i]['ticked'] = true;
}
}
}
for (var i = 0; i < $scope.parents.length; i ++){
if ($scope.parents[i].id == product.parent.id){
$scope.parents[i]['ticked'] = true;
}
}
console.log('Products', product);
$scope.product = product;
});
};
This code, sometimes, it works, sometimes it doesn't, because in the findOne function, sometimes, the $scope.ages $scope.skinissues $scope.skintypes or $scope.activities is undefined.
This happens because their queries haven't finished yet.
What can I do to solve this problem?
Please help. Thanks.
Use $q.all to resolve the $resource promises.
angular.module('mean.variables')
.factory('Variables', function($q, Products, Ages, Activities, Skinissues, Skintypes, _){
return {
get: function(){
var promiseHash = {};
promiseHash.ages = Ages.query().$promise;
promiseHash.skinissues = Skinissues.query().$promise;
promiseHash.skintypes = Skintypes.query().$promise;
promiseHash.activities = Activities.query().$promise;
promiseHash.parents = Products.query().$promise;
return $q.all(promiseHash);
}
}
});
The above example function returns a promise that either resolves sucessfully to a hash of the query objects or resolves rejected with the first rejected response object.
The advantage of using $q.all() instead of $q.defer is that the promise chains aren't broken and error responses are retained for clients of the factory.
From the Docs:
The Resource instances and collections have these additional properties:
$promise: the promise of the original server interaction that created this instance or collection.
On success, the promise is resolved with the same resource instance or collection object, updated with data from server. This makes it easy to use in resolve section of $routeProvider.when() to defer view rendering until the resource(s) are loaded.
On failure, the promise is rejected with the http response object, without the resource property.
If an interceptor object was provided, the promise will instead be resolved with the value returned by the interceptor.
--AngularJS ngResource API Reference
all(promises);
Combines multiple promises into a single promise that is resolved when all of the input promises are resolved.
Parameters
An array or hash of promises.
Returns
Returns a single promise that will be resolved with an array/hash of values, each value corresponding to the promise at the same index/key in the promises array/hash. If any of the promises is resolved with a rejection, this resulting promise will be rejected with the same rejection value.
--AngularJS $q Service API Reference -- $q.all
Thanks guy, I've came up with this service by using setInterval to check if all variable are defined.
angular.module('mean.variables')
.factory('Variables', ['$q', 'Products', 'Ages', 'Activities', 'Skinissues', 'Skintypes', '_', function($q, Products, Ages, Activities, Skinissues, Skintypes, _){
return {
get: function(){
var variables = {};
var defer = $q.defer();
Ages.query(function(res){
variables.ages = res;
});
Skinissues.query(function(res){
variables.skinissues = res;
});
Skintypes.query(function(res){
variables.skintypes = res;
});
Activities.query(function(res){
variables.activities = res;
});
Products.query(function(res){
variables.parents = res;
});
var timer = setInterval(function(){
if (variables.ages && variables.activities && variables.skinissues && variables.skintypes && variables.parents){
defer.resolve(variables);
clearInterval(timer);
}
}, 50);
return defer.promise;
}
}
}])

Resources