Using AngularJs 1.6.5 I am making multiple $http GET calls using the for loop. Here is the code:-
for(var i=0; i < 11; i++){
var url = "/api/learner_qa/" + i;
$http.get(url).then(successCallback, errorCallback);
function successCallback(response){
console.log(response);
};
function errorCallback(error){
console.log(error);
};
};
What I want to do is trigger a function when all the GET requests are completed.
I referred to answer posted here and want to know how can this be done on an array as in my case?
The time will likely arise where you need to resolve multiple promises
at once, this is easily achieved through $q.all() by passing in either
an Array or Object of promises which will call .then() once both are
resolved:
You can take an array and push your http calls into it
var array = [];
for(var i=0; i < 11; i++){
var url = "/api/learner_qa/" + i;
array.push($http.get(url))
};
$q.all(array).then(function(response) {
console.log(response)
}).catch(function(error){
console.log(error)
});
Using this code, the response will come once all your requests are successful.
Here is an example documentation
Related
First of all I want to use $http in order to receive some data (e.g. students), then I want to make another $http call to get e.g. studentDetails. After that I want to append some part of studentDetails to students JSON.
Also I need response from the first call in order to create the url for the second call.
Problem is that I cannot access response of the first http call inside the another.
Does anybody know how this can be done?
var getStudents = function(){
var deferred = $q.defer();
$http.get("https://some_url")
.success(function(response){
deferred.resolve(response);
}).error(function(errMsg){
deferred.reject(errMsg);
});
return deferred.promise;
}
var appendStudentDetails = function(){
getStudents().then(function(response){
var studentsWithDetails = response;
for(var i=0; i<studentsWithDetails.length; i++){
$http.get("some_url/"+studentWithDetails[i].user.details+"/")
.success(function(res){
//here I want to append the details,
//received from the second http call, to each student
//of the array received from the first http call
//PROBLEM: I cannot access response of the
//first http call inside the another
})
}
})
You're using the deferred anti-pattern as well as the deprecated success/error-callbacks. You should instead use then, since it returns a promise, and you can chain promises.
Here's an example of how you could do it:
function getStudents(){
return $http.get('[someurl]');
}
function appendStudentDetails(studentsWithDetails){
for(var i=0; i<studentsWithDetails.length; i++){
appendSingleStudentDetails(studentsWithDetails[i]);
}
}
function appendSingleStudentDetails(singleStudent){
$http.get("some_url/"+singleStudent.user.details+"/")
.then(function(res){
// Append some stuff
singleStudent.stuff = res.data;
});
}
// Call it like this:
getStudents()
.then(function(response){ return response.data; })
.then(appendStudentDetails);
I decided to structure the appendStudentDetails function a little differently, based on its name, but you could as easily just call getStudents() within the method as you did before.
Beware not to use the i-variable inside your inner then-function, as that would cause you troubles with closure.
Edit: Fixed example to avoid problem with i being under closure.
///Returning JSON 1
$http.get("url1").
then(function (response) {
$scope.foo = response.data;
});
///Returning JSON 2
$http.get("url2").
then(function (response) {
$scope.foo = response.data;
});
///Returning JSON (n)
$http.get("n").
then(function (response) {
$scope.foo = response.data;
});
Can I somehow concat these JSON objects into one? The reason is that I have ALOT of data and since I rather would like to display alot of data for the user to filter through than to have them click through 1000 pages in a SPA, I would like to join them if that's possible (in a reasonable manner ofcourse).
EDIT
I was thinking something like this
var url ="";
for (... i < 100...) {
url = "http://url.com"+i+"";
$http.get(url).
then(function(response){
$scope.foo.concat(response.data);
}
);
}
Update
I've managed to join the JSON returns into an array of objects. But the problem is that this array now contains objects which in itself contains an object which in itself contains an array of objects... yup!
If it's array then you can concat it.
Initialize empty array first
$scope.foo = [];
$http.get("url1").
then(function (response) {
$scope.foo.concat(response.data);
});
Use $q.all to create a promise that returns an array:
function arrayPromise(url, max)
var urlArray = [];
for (let i=0; i<max; i++) {
urlArray.push(url + i);
};
var promiseArray = [];
for (let i=0; i<urlArray.length; i++) {
promiseArray.push($http.get(urlArray[i]);
};
return $q.all(promiseArray);
});
To fetch nested arrays, chain from the parent:
function nestedPromise (url, max) {
var p1 = arrayPromise(url + "item/", max);
var p2 = p1.then(function(itemArray) {
var promises = [];
for (let i=0; i<itemArray.length; i++) {
var subUrl = url + "item/" + i + "/subItem/";
promises[i] = arrayPromise(subUrl, itemArray[i].length);
};
return $q.all(promises);
});
return p2;
};
Finally resolve the nested promise:
nestedPromise("https://example.com/", 10)
.then(function (nestedArray) {
$scope.data = nestedArray;
});
It is important to use a return statement at all levels of the hierarchy: in the .then methods and in the functions themselves.
Chaining promises
Because calling the .then method of a promise returns a new derived promise, it is easily possible to create a chain of promises.
It is possible to create chains of any length and since a promise can be resolved with another promise (which will defer its resolution further), it is possible to pause/defer resolution of the promises at any point in the chain. This makes it possible to implement powerful APIs.
— AngularJS $q Service API Reference - Chaining Promises
You can wait for the n requests to finish and then do whatever you want with the object returned.
$q.all($http.get("url1"), $http.get("url2"), $http.get("url3"))
.then(function (responses) {
// This function is called when the three requests return.
// responses is an array with the first item being the result of
// fetching url1, the second fetching url2, etc.
// Depending on what the response looks like you may want to do
// something like:
$scope.data = angular.merge(responses[0], responses[1] /* etc */);
});
Is It possible generating a sort of documentation,
where are addressed all HTTP requests sendable by a specific Angular Application?
try to store the url addresses into an array and then loop the HTTP request call.
Something like this maybe:
for (var i=0 ; i < $scope.urls.length ; i++)
{
$http.get($scope.urls[i])
.success(function(response){
$scope.results[i] = response.data;
})
.error(function(response){
$scope.errors[i] = response.error;
$scope.errormessages[i] = response.errormessage;
});
}
And using scope.$evalAsync(function () {}) if needed to synchronous the call.
I have an AngularJs app in which I need to make $http post calls in a loop. Here is my code:
var promisesArray = [];
for(i = 0; i < 28; i++) {
promisesArray.push($http({
method: "post",
url: "/studentanswers",
data: {
studentName: "abc",
answerImage: "sdf",
questionPrompt: 1
}
}));
}
$q.all(promisesArray).then(function(data){
console.log("success!!!!");
});
For some reason, it is not posting all the items in the collection. I am aware that browsers usually do not allow more than 6 async post calls. From what I understood, $q.all was a way around it. Also, even if I comment out the $q.all part, it doesn't matter because the post calls get executed nonetheless.
I would greatly appreciate any help!
Be aware that $q.all is not resilient. It will terminate with the first rejected promise. But that really isn't your problem.
You need to chain your posts to avoid the browser limit of simultaneous posts.
var promisesList = [];
var promiseMinusOne = $q.when();
for (var i = 0; i < 28; i++) {
//begin IIFE closure
function(i) {
//chain off promiseMinusOne
var httpPromise =
promiseMinusOne.catch (function (e) {
return e;
}) .then (function (r) {
return $http({ method: "post",
url: "/studentanswers",
data: answerList[i]
})
});
promisesList.push(httpPromise);
promiseMinusOne = httpPromise;
}(i);
//end IIFE closure
};
var chainablePromise =
promiseMinusOne.catch (function (e) {
return (e);
}) .then (function (r) {
//process the promisesList
});
Notice, that for promiseMinusOne, the use of .catch and return in order to continue the list in the event of a rejection of one of the items.
while I'm getting a json object from Restangular ,another rest url function has been called(before first response comes)
Restangular.all("..").getList("..").then(
function(data){
$scope.dataList = data.dataList;
}, function errorCallback() {
alert("error");
}
);
here before initializing datalist it is calling another function parallely? how can I avoid this?
thanks.
If you need to call your services in specific order then you have two options:
Nesting service callbacks. This solution will prevent execution of the next ajax call until the previous is finished:
Restangular.all("..").getList("..").then(
function(data){
Restangular.secondFunction("..").getList().then(
function (data2) {
// both data and data2 are available
});
}, function errorCallback() {
alert("error");
}
);
Use $q.all() function which waits for the array of deferred objects to finish:
var promises = [];
promises.push(Restangular.all("..").getList(".."));
promises.push(Restangular.secondFunction("..").getList());
$q.all(promises).then(function (results) {
for (var i=0; i<results.length; i++)
{
// all ajax calls have finished now you can iterate through the results
}
});
BTW there is no such thing like parallel execution in javascript.