rest urls calls parallely angularjs - angularjs

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.

Related

$q.all - access individual promise result?

I'm a bit new to $q angular promises. Here is my code structure:
$q.all(promises).then(function(results) {
results.forEach(function(data, status, headers, config) {
console.log(status);
});
$scope.saveDocumentCaseState();
}, function errorCallBack(response) {
console.log('error while mass update case entries');
console.log(response);
$scope.submitToWsSuccessful = 2;
});
Is there a possibility to access the result of each promise when it has been executed before the next one?
So assuming that you receive an array with an arbitrary number of promises from an angular factory called promiseFactory:
var promises = promiseFactory.getPromises(); // Returns an array of promises
promises.forEach(function(p){
p.then(promiseSuccess, promiseError);
function promiseSuccess(){
// Do something when promise succeeds
}
function promiseError(){
// Do something when promise errors
}
});
$q.all(promises).then(allSuccess, allError);
function allSuccess(){
// All calls executed successfully
}
function allError(){
// At least one of the calls failed
}

Use response from one $http in another $http in Angularjs

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.

How to concat JSON objects from different URLs with nested resources

///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 */);
});

How to defer loop wrapped $http get request in angular js?

I have a function that checks for for records and if they exist it downloads them for each item. This is a function that happens with in a loop so there can me many records. I thought that I was using $Q properly to deffer each $http request to wait for one after each other so they do not all happen at the same time but they all fire at the same time still.
I have seen $q.defer(); but do not understand how to use it in my implementation. How would this be written properly deferring each call until the one before is complete?
CheckRecords: function(obj) {
var promise;
var promises = [];
if (obj.BD.img == 'checkedRecord') {
var objBDUrl = 'services/GetSurveyBD/?id=' + obj.BD.ID;
promise = $timeout(function(){
$http.get(objBDUrl, { cache: true }).then(function(response) {
obj.BD.ID = obj.BD.ID;
obj.BD.data = response.data;
});
}, 250);
promises.push(promise);
}
if (obj.MR.img == 'checkedRecord') {
var objMRUrl = 'services/GetMR/?id=' + obj.MR.ID;
promise = $timeout(function(){
$http.get(objMRUrl, { cache: true }).then(function(response) {
obj.MR.ID = obj.MR.ID;
obj.MR.data = response.data;
});
}, 250);
promises.push(promise);
}
$q.all(promises).then(function(){
return obj;
});
}
The function $q.all just ensures that all requests completed, the requests are still executed immediately, but their results are deferred. If you want to control the execution order you, do your requests in the result function.
$q
- service in module ng
A service that helps you run functions asynchronously, and use their return values (or exceptions) when they are done processing.

Subsequent ajax calls in angularJs

I'd like to make subsequent ajax calls in angularJs inside a service.
I've tried with something like this:
var requests = [
{'url': 'call1'},
{'url': 'call2'},
{'url': 'call3'}
];
return $q.all([
$http({
url: requests[0],
method: "POST"
}).then( /*callback*/ ),
$http({
url: requests[1],
method: "POST"
}).then( /*callback*/ )
]);
But this make alla ajax in parallel. I need a way to make this calls subsequent, so after first end, it calls second....
You can chain promises:
var requests =[{'url':'index.html'},
{'url':'index.html'},
{'url':'index.html'}];
function makeCall(n) {
return $http({url:requests[n].url+"?n="+n,method:"GET"}).then(function(r) {
if (n+1<requests.length) return makeCall(n+1);
});
}
makeCall(0);
http://plnkr.co/edit/1HdYUtHKe8WXAFBBq8HE?p=preview
You could use async.eachSeries:
var requests = ['call1', 'call2', 'call3'];
function iterator(request, done) {
$http({
url: request,
method: "POST"
}).then(done);
};
async.eachSeries(
requests,
iterator,
function (err) {
// Done
}
);
From the readme:
eachSeries(arr, iterator, callback)
The same as each only the iterator is applied to each item in the array in series. The next iterator is only called once the current one has completed processing. This means the iterator functions will complete in order.
arr - An array to iterate over.
iterator(item, callback) - A function to apply to each item in the array. The iterator is passed a callback(err) which must be called once it has completed. If no error has occured, the callback should be run without arguments or with an explicit null argument.
callback(err) - A callback which is called after all the iterator functions have finished, or an error has occurred.
You should be able to call another $http call in the "then" callback, returning the return value of $http
$http({...})
.then(function() {
return $http({...});
})
.then(function() {
return $http({...});
});
This works because each call to $http returns a promise. If you return a promise in the "then" success callback, then the next "then" callback in the chain will be deferred until that promise is resolved, which will be when the ajax call completes.
Edit: In response to the comment, you can loop over an array of requests:
var requests = [
{'url':'call1','method':'get'},
{'url':'call2','method':'get'},
{'url':'call3','method':'get'}
];
var promise = null;
angular.forEach(requests, function(details) {
promise = $q.when(promise).then(function() {
return $http(details);
});
});
As in the Plunker at http://plnkr.co/edit/RSMN8WuPOpvdCujtrrZZ?p=preview . The $q.when is just for the first value of the loop, when promise is set to null, so it has a then callback that is called immediately.

Resources