I have an ID array contains with 50+ id.
var ids = [
'3407197',
'0632706',
'18275',
...,
...
]
I want to send angular HTTP get request with a loop. Each iteration will delay 10 sec delay. When all the request complete it will notify that request are completed.
I have tried with this code but It executes at once not delaying.
function collector(i){
setTimeout(function() {
return $http.get('http://example.com/' + ids[i])
.success(function(data) {
})
.error(function(err) {
})
},10000);
}
$scope.getAllData = function() {
var promises = [];
for (var i = 0; i < ids.length; i++) {
promises.push(collector(i));
}
return $q.all(promises);
}
$scope.getAllData ().then(function(data) {
$scope.debug = 'done';
});
Try with $timeout:
function getRequest(id) {
return $http.get('http://example.com/' + id)
.success(function (data) {})
.error(function (err) {});
}
var promise = $timeout();
ids.forEach(function(id) {
promise = promise.then(function() {
getRequest(id);
return $timeout(10000);
});
});
// not sure if this works
promise.then(function() {
$scope.debug = 'done';
});
Related
Promise in ForEach
I'm having a problem, I need to call a service N times and I've tried this:
This is my function that calls the service, I send a parameter that is "code" and returns a promise.
var get222 = function(codigo) {
var defer = $q.defer();
var cbOk = function(response) {
//console.log(response);
defer.resolve(response);
}
var cbError = function(error) {
//console.log(error);
defer.reject(error);
}
VentafijaAccessService.getProductOfferingPrice(codigo, cbOk, cbError);
return defer.promise;
}
After this function, I get the codes and I need to make a call N times and when they finish returning the promise to get the answer for each code I send.
var getProductOfferingPrice = function(_aCodigoOfertas) {
var deferred = $q.defer();
var results = [];
var promises = [];
angular.forEach(_aCodigoOfertas, function(codigo) {
promises.push(get222(codigo));
});
$q.all(promises)
.then(function(results) {
// here you should have all your Individual Object list in `results`
deferred.resolve({
objects: results
});
});
return deferred.promise;
};
The calls to the services IF THEY ARE EXECUTED, but never returns the promise, I can not get the response of each one.
EDIT
VentaDataService.js
var get222 = function(codigo) {
return $q(function(resolve, reject) {
VentafijaAccessService.getProductOfferingPrice(codigo, resolve, reject);
});
}
var getProductOfferingPrice = function(_aCodigoOfertas) {
return $q.all(_aCodigoOfertas.map(function(codigo) {
return get222(codigo);
}));
};
VentaFijaController.js
var cbOk2 = function(response) {
console.log(response);
}
var cbError2 = function(error) {
console.log(error);
}
VentafijaDataService.getProductOfferingPrice(codigoOfertas)
.then(cbOk2, cbError2)
There's no need to wrap a new promise around this. Just return the $q.all() promise:
VentafijaAccessService.getProductOfferingPriceAllPromise = function(_aCodigoOfertas) {
var promises = [];
angular.forEach(_aCodigoOfertas, function(codigo) {
promises.push(get222(codigo));
});
return $q.all(promises);
};
The resolved value of the returned promise will be an array of results.
VentafijaAccessService.getProductOfferingPriceAllPromise(...).then(results => {
console.log(results);
}).catch(err => {
console.log(err);
});
If _aCodigoOfertas is an array, you can further simply getProductOfferingPrice to this:
VentafijaAccessService.getProductOfferingPriceAllPromise = function(_aCodigoOfertas) {
return $q.all(_aCodigoOfertas.map(function(codigo) {
return get222(codigo);
}));
};
You can also vastly simplify get222() to this:
var get222 = function(codigo) {
return $q(function(resolve, reject)) {
// call original (non-promise) implementation
VentafijaAccessService.getProductOfferingPrice(codigo, resolve, reject);
});
}
Then, in the controller, you could do this:
VentafijaDataService.getProductOfferingPriceAllPromise(codigoOfertas).then(function(result) {
console.log(result);
}).catch(function(e) {
console.log('Error: ', e);
});
Am trying to call a Post method and then depending on the result I am going to call same Post method multiple times and return the result, using $q.all.
My Post method is :
getData: function (params, callback) {
$http.post('service/myService', params)
.success(function (data) {
callback(null, data);
}).error(function (error) {
callback(error);
});
}
I am calling it in below function, this function is recursive so if it contains nextUrl I am doing same thing until there is no object for paging:
var result = [];
var promises = [];
var checkForPaging = function (nextUrl, service, $q) {
var deferred = $q.defer();
var criteria = {
url: url
}
var promise = service.getData(criteria, function (error, data) {
if (data.statusCode == 200) {
for (var i = 0; i < data.body.items.length; i++) {
result.push(data.body.items[i]);
}
if (data.body.paging != null && data.body.paging.next != null) {
checkForPaging(data.body.paging.next.url, service, $q);
} else{
deferred.resolve(result);
}
}
});
promises.push(promise);
$q.all(promises)
return deferred.promise;
}
Then am calling this function from below and want to get the result back once all calls are complete:
checkForPaging(data.body.paging.next.url, myService, $q).then(function (data) {
console.log(data)
});
The issue I am having is that it never hits the callback function above : console.log(data). But I can see it calling the Post method several times.
If I resolve it like below then I can see after first Post it is hitting the callback above:
$q.all(promises).then(function (results) {
deferred.resolve(result);
}, function (errors) {
deferred.reject(errors);
});
Am I doing it right? How can I get the result back and call the Post method several times?
Let me know if it is not clear or have any questions!
Try something like this with proper promise chaining:
var result = [];
var checkForPaging = function(nextUrl, service) {
var criteria = {
url: url
}
return service.getData(criteria, function(error, data) {
if (data.statusCode == 200) {
for (var i = 0; i < data.body.items.length; i++) {
result.push(data.body.items[i]);
}
if (data.body.paging != null && data.body.paging.next != null) {
return checkForPaging(data.body.paging.next.url, service);
} else {
return result;
}
}
});
}
checkForPaging(data.body.paging.next.url, myService).then(function(data) {
console.log(data)
});
And getData:
getData: function(params) {
return $http.post('service/myService', params)
.then(function(response) {
return response.data;
});
}
Here is solution: https://plnkr.co/edit/HqkFNo?p=preview I rewrited logic a bit.
You can catch the main idea.
UPDATE added promiseless solution
1) Your service should return only promise:
this.getData = function(url, params){
return $http.post(url, params); //You're just returning promise
}
2) You don't need $q.all, you can use single promise:
var result = [];
var deferred;
var checkForPaging = function (url) {
if(!deferred){
deferred = $q.defer();
}
//resolvind service promise
newService.getData(url).then(
//if ok - 200
function(response){
for (var i = 0; i < data.body.items.length; i++) {
result.push(data.body.items[i]);
}
if (data.body.paging != null && data.body.paging.next != null){
{
return checkForPaging(data.body.paging.next.url);
} else{
deferred.resolve(result);
}
},
//handle errors here
function(error) {
}
);
return deferred.promise;
}
3) You should call it like this:
checkForPaging('url').then(function(data){
//here will be resolved promise
console.log(data);
});
I have the following in my controller:
ApiRequest.get('locations').then(function(locations) {
$scope.locations = locations.locations;
});
ApiRequest.get('sublocations').then(function(sublocations) {
$scope.sublocations = sublocations.sublocations;
});
ApiRequest.get('varieties').then(function (varieties) {
$scope.varieties = varieties.varieties;
});
ApiRequest.get('tasks').then(function(tasks) {
$scope.tasks = tasks.tasks;
});
ApiRequest.get('customers').then(function(customers) {
$scope.customers = customers.customers;
});
ApiRequest.get('batches').then(function(batches) {
$scope.batches = batches.batches;
$ionicLoading.hide();
});
The data from each of these requests goes on to poplate select boxes in a form.
Here is my APIRequest service:
return {
get: function(entity) {
if($rootScope.online == false) {
var data = {};
data = JSON.parse(localStorage.getItem('data-' + entity));
console.log(data);
deferred.resolve(data);
} else {
$http.get($rootScope.baseUrl + entity).success(function(data) {
deferred.resolve(data);
})
}
return deferred.promise;
},
}
It would appear that for some reason the results aren't getting back from the service on time to display them in the view.
Is this something to do with the way I am handling the promise?
At first look, you declared the promise with $q outside your function as global (because I don't see inside). Try this one:
get: function(entity) {
var deferred = $q.defer();
if($rootScope.online == false) {
var data = {};
data = JSON.parse(localStorage.getItem('data-' + entity));
console.log(data);
deferred.resolve(data);
} else {
$http.get($rootScope.baseUrl + entity).success(function(data) {
deferred.resolve(data);
})
}
return deferred.promise;
},
your current implementation has little to no error handling and is executing multiple API requests in parallel; I would recommend chaining the promises.
ApiRequest.get('locations').then(function(locations) {
$scope.locations = locations.locations;
return ApiRequest.get('sublocations');
}).then(function(sublocations) {
$scope.sublocations = sublocations.sublocations;
return ApiRequest.get('varieties')
}).then(function (varieties) {
$scope.varieties = varieties.varieties;
return ApiRequest.get('tasks')
}).then(function(tasks) {
$scope.tasks = tasks.tasks;
return ApiRequest.get('customers')
}).then(function(customers) {
$scope.customers = customers.customers;
return ApiRequest.get('batches')
}).then(function(batches) {
$scope.batches = batches.batches;
$ionicLoading.hide();
}, function(_error) {
$ionicLoading.hide();
console.log(_error);
});
and then your service can be simplified; the $http client returns a promise and using $q.when can return a promise also
get: function(entity) {
if($rootScope.online == false) {
var data = {};
data = JSON.parse(localStorage.getItem('data-' + entity));
console.log(data);
$q.when(data);
} else {
return $http.get($rootScope.baseUrl + entity)
}
},
I'm trying to make couple of HTTP requests, one inside another, and I'm having a trouble restructuring my JSON object.
I have a factory function, first of all i'm trying to get all the teams, each team has an Id, and then i'm getting all the news for each team with the id related, and putting that news in the first JSON object.
but this is not working !
.factory('teamsFactory', function ($http,CacheFactory,LocaleManager,$q)
{
teams.Getteams= function()
{
var zis=this;
var promise=$http({method:"GET",url:"http://www.myserver/teams"});
promise.then(function(response){
for (var i=0;i<response.data.length;i++) {
zis.getTeamsNews(response.data[i].idTeam).then(function(newsresponse){
response.data[i].news=newsresponse.data;
});
}
},alert('error'));
return promise;
}
teams.getTeamsNews= function(idTeam)
{
var promise=$http({method:"GET",url:"http://www.myserver.com/news?team="+idTeam});
promise.then(null,alert('error'));
return promise;
}
});
I think it's better to push all the $http promises into an array and then use $q.all() to group them together rather than calling them each individually in a loop. Try this:
Note I had to move some of your functions around and create dummy data etc. so you will have to alter it slightly to fit your app.
DEMO
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope, teamsFactory) {
$scope.name = 'World';
teamsFactory.Getteams()
.then(function(data){
$scope.teamsData = data;
});
});
app.factory('teamsFactory', function ($http, $q){
var teams = {};
teams.getFavoriteTeamsNews = function(teamId){
return $http
.get('news.json')
.then(function(response){
console.log('gtTeamNews response', response);
return response.data[teamId];
})
}
teams.Getteams = function(){
var zis = this,
httpConfig = {
method : "GET",
url : "teams.json"
};
return $http(httpConfig)
.then(function(response){
var teamId, promise,
requests = [];
for(var i = 0; i <response.data.length; i++){
teamId = response.data[i].idTeam;
promise = teams.getFavoriteTeamsNews(teamId);
requests.push(promise);
}
return $q
.all(requests)
.then(function(responses){
angular.forEach(responses, function(newsresponse, index){
response.data[index].news = newsresponse;
});
return response.data;
});
})
.catch(function(error){
console.log('error', error);
});
}
return teams;
// teams.TeamsNews= function(idTeam){
// return $http({method:"GET",url:"http://www.myserver.com/news?team="+idTeam})
// .catch(function(){
// alert('error')
// });
// }
});
update
You could also re-factor the above to take advantage of promise chaining which makes it much cleaner in my opinion. This should give the same output but is more 'flat', i.e. has less indentation/callback hell:
DEMO2
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope, teamsFactory) {
$scope.name = 'World';
teamsFactory.Getteams()
.then(function(data){
$scope.teamsData = data;
});
});
app.factory('teamsFactory', function ($http, $q){
var responseData,
teams = {};
teams.getFavoriteTeamsNews = function(teamId){
return $http
.get('news.json')
.then(function(response){
console.log('gtTeamNews response', response);
return response.data[teamId];
})
}
teams.Getteams = function(){
var zis = this,
httpConfig = {
method : "GET",
url : "teams.json"
};
return $http(httpConfig)
.then(function(response){
var teamId, promise,
requests = [];
responseData = response.data;
for(var i = 0; i < responseData.length; i++){
teamId = responseData[i].idTeam;
promise = teams.getFavoriteTeamsNews(teamId);
requests.push(promise);
}
return $q.all(requests);
})
.then(function(responses){
angular.forEach(responses, function(newsresponse, index){
responseData[index].news = newsresponse;
});
return responseData;
})
.catch(function(error){
console.log('error', error);
});
}
return teams;
});
eventually something like that .. this is raw solution .. could be enhanced with caching ...
var module = angular.module('myapp', []);
module.factory('teamsFactory', function ($http,CacheFactory,LocaleManager,$q)
{
function ExtractTeamFromData(data){
// TODO
console.log("TODO: Exctract teams from data ...");
}
function FindTeamById(teams, tgeamId){
// TODO
console.log("TODO: Find team by id ...");
}
function ExtractNewsFromData(data){
// TODO
console.log("TODO: Exctract news from data ...");
}
var GetTeams= function()
{
var zis=this;
var promise = $http({method:"GET",url:"http://www.myserver/teams"});
var successCallback = function(data, status, headers, config) {
var teams = ExtractTeamFromData(data);
return teams;
};
var errorCallback = function(reason, status, headers, config) {
console.error("Some error occured: " + reason);
return {
'errorMessage': reason
};
}
promise.then(successCallback,errorCallback);
return promise;
}
var GetTeam = function(idTeam)
{
var promise = GetTeams();
var successTeamsCallback = function(teams, status, headers, config) {
return FindTeamById(teams, tgeamId);
};
var errorTeamsCallback = function(reason, status, headers, config) {
console.error("Some error occured: " + reason);
return {
'errorMessage': reason
};
}
promise.then(successTeamsCallback,errorTeamsCallback);
return promise;
}
var GetTeamsNews = function(idTeam){
var promise = GetTeam(idTeam);
var successTeamCallback = function(team, status, headers, config) {
var newsPromise = $http({method:"GET",url:"http://www.myserver.com/news?team="+idTeam});
var successNewsCallback = function(data, status, headers, config) {
var news = ExtractNewsFromData(data);
return news;
};
var errorNewsCallback = function(reason, status, headers, config) {
console.error("Some error occured: " + reason);
return {
'errorMessage': reason
};
}
newsPromise.then(successNewsCallback,errorNewsCallback);
return newsPromise;
};
var errorTeamCallback = function(reason, status, headers, config) {
console.error("Some error occured: " + reason);
return {
'errorMessage': reason
};
}
promise.then(successTeamCallback,errorTeamCallback);
return promise;
}
return {
GetTeams: GetTeams,
GetTeam: GetTeam,
GetTeamsNews: GetTeamsNews
};
});
You need to create a promise of your own, and resolve it when done, this way :
return $q(function(resolve, reject) {
$http({method:"GET",url:"http://www.myserver/teams"}).then(function(response){
var promises = [];
for (var i=0;i<response.data.length;i++) {
promises.push(zis.getFavoriteTeamsNews(response.data[i].idTeam)).then(function(newsresponse){
response.data[i].news=newsresponse.data;
});
}
$q.all(promises).then(function(){
resolve(response);
});
});
for (var i=0;i<response.data.length;i++) {
zis.getFavoriteTeamsNews(response.data[i].idTeam).then(function(newsresponse){
response.data[i].news=newsresponse.data;
})
});
How do I create 1 callback function for multiple http in angularjs. My code:
for (var i = 0; i < docs.length; i++) {
this.base64(docs[i], function(base64Img){
$http.post(urls.BASE + '/store',{doc:base64Img}).then(
function(result) {
console.log(result);
}
);
});
}
mycallback.call(); <-- this should be done when all my http.post above are done.
Use $q.all():
var deferred = $q.defer();
var httpPromises = [];
for (var i = 0; i < docs.length; i++) {
this.base64(docs[i], function(base64Img) {
httpPromises.push($http.post(urls.BASE + '/store',{doc:base64Img});
if (httpPromises.length === docs.length) {
deferred.resolve();
}
}));
}
return deferred.promise.then(function() {
return $q.all(httpPromises);
});
Note that if this.base64() returned a promise rather than taking a callback in argument, that would be simpler:
var promises = [];
for (var i = 0; i < docs.length; i++) {
promises.push(this.base64(docs[i]).then(function(base64Img) {
return $http.post(urls.BASE + '/store',{doc:base64Img});
}));
}
return $q.all(promises);
or even
return $q.all(docs.map(function(doc) {
return this.base64(doc).then(function(base64Img) {
return $http.post(urls.BASE + '/store',{doc:base64Img});
});
});
Okay so I created a HttpInterceptor Service for this so every time a request starts it checks if there are more requests within a certain timelimit and then after all of those requests responded It broadcasts "all requests done".
For that to work I embeded my Intercepter like this in my App.js
.config(function ($httpProvider) {
$httpProvider.interceptors.push('httpInterceptor');
})
And my service looks like this basicly there is a variable numloadings which counts the requests up and when there is a respones it counts them down when it reaches 0 all requests went through
.factory('httpInterceptor', ['$q', '$rootScope', '$filter', function ($q, $rootScope, $filter) {
var canceller = $q.defer();
var numLoadings = 0;
var serialRequests = false;
var timeO;
var time1;
var Cntr1 = 0;
var Cntr2 = 0;
var currentReqUrl;
$rootScope.broadcast = true;
var loadingbar = { loading: "<progress value='?' max='10'></progress>" };
var loadingspinner = { loading: '<ion-spinner icon="crescent"></ion-spinner>' };
return {
request: function (config) {
config.timeout = 200000;
numLoadings++;
if (serialRequests == false) {
$rootScope.$broadcast("open_requests", loadingspinner);
} else {
clearTimeout(timeO);
}
}
return config || $q.when(config)
},
response: function (response) {
serialRequests = true;
numLoadings--;
timeO = setTimeout(function () {
serialRequests = false
if ((numLoadings) === 0) {
$rootScope.$broadcast("all_requests_done");
}
});
}
return response || $q.when(response);
},
responseError: function (response) {
serialRequests = true;
numLoadings--;
timeO = setTimeout(function () {
serialRequests = false
if ((numLoadings) === 0) {
$rootScope.$broadcast("all_requests_done");
}
});
}
return $q.reject(response);
}
};