How to bundle Angular $http.get() calls? - javascript

I have a controller that needs to retrieve two separate REST resources that will populate two dropdowns. I would like to avoid populating either of them until both $http.get() calls have returned, so that the dropdowns appear to be populated at the same time, instead of trickling in one after the other.
Is it possible to bundle $http.get() calls and elegantly set the $scope variables for both returned arrays, without having to write state logic for both scenarios, e.g. a returns before b, b returns before a?

The return value of calling the Angular $http function is a Promise object using $q (a promise/deferred implementation inspired by Kris Kowal's Q).
Take a look at the $q.all(promises) method documentation:
Combines multiple promises into a single promise that is resolved when
all of the input promises are resolved.
Parameters
promises – {Array.<Promise>} – An array of promises.
Returns
{Promise} – Returns a single promise that will be resolved with an array of values, each value corresponding to the promise at the same index in the promises array. If any of the promises is resolved with a rejection, this resulting promise will be resolved with the same rejection.
You can use $q.all to "join" the results of your http calls, with code similar to:
app.controller("AppCtrl", function ($scope, $http, $q) {
$q.all([
$http.get('/someUrl1'),
$http.get('/someUrl2')
]).then(function(results) {
/* your logic here */
});
}

do you mean something like this:
function someController( $scope, $http, $q ) {
var first_meth = $http.get("first_url"),
second_meth = $http.get("second_url");
$q.all([first_meth, second_meth]).then(function(all_your_results_array) {
//here you'll get results for both the calls
});
}
Ref: Angular JS Doc

You could use the Async javsscript library here: https://github.com/caolan/async.
Use the series call. It will make the 2 calls and then call one callback when both are done.

Related

Can anyone explain the use of $q service in angularjs? [duplicate]

This question already has answers here:
AngularJS Promises, $q, defer
(2 answers)
Closed 5 years ago.
I am new to angularjs.I saw $q in restful api calls to check the promise.
$q.defer() was used to retain the promise object.
I read about the promises but I didn't get anything.
although I can make the api call without $q, however it is used somewhere in articles.
So I want to know the exact use of $q and difference in making api calls without $q.
Kindly help.
thanks
I think the article I wrote about $q might help you.
Introduction to $q
$q is an angular defined service. It’s the same as new Promise(). But $q takes things to the next level by enhancing additional feature that developers can use to perform complex tasks more simply.
This is a sample for creating a promise using $q
angular.module("app",[])
.controller("ctrl",function($scope,$q){
var work = "resolve";
var promise = $q(function(resolve, reject) {
if (work === "resolve") {
resolve('response 1!');
} else {
reject('Oops... something went wrong');
}
});
promise.then(function(data) {
alert(data)
})
})
$q.defer()
$q.defer() return the instance of the promise constructor. Once you create a defer object there are following methods and properties that you can access from that object
resolve(value) – resolves the derived promise with the value. If the value is a rejection constructed via $q.reject, the promise will be rejected instead.
reject(reason) – rejects the derived promise with the reason. This is equivalent to resolving it with a rejection constructed via $q.reject.
notify(value) - provides updates on the status of the promise's execution. This may be called multiple times before the promise is either resolved or rejected.
promise – {Promise} – promise object associated with this deferred
See the example
angular.module("app",[])
.controller("ctrl",function($scope,$q){
var work = "resolve";
function getData(){
var obj = $q.defer();
if (work === "resolve") {
obj.resolve('response 1!');
} else {
obj.reject('Oops... something went wrong');
}
return obj.promise;
}
getData().then(function(data) {
alert(data)
})
})
$q.all()
If a user need to send multiple request one shot,then the user can use $q.all() service.
$q.all([$http.get('data1.json'),$http.get('data2.json')])
.then(function(response){
console.log(response[0].data) // data1.json response
console.log(response[1].data) // data1.json response
})
In here,there are two http request sent simultaneously to two separate JSON files to get data. The response comes as an array and response order is same as the HTTP request order.
$q.race()
$q.race() is very similar to $q.all(). But instead of sending response of each request, it will only return the one request response. Specifically, only return the response of first request that been executed. That does not mean it’s not going to send other requests. All the requests are sending but it's only return the response of the first request that executed.
$q.race([$http.get('data1.json'),$http.get('data2.json')])
.then(function(response){
console.log(response[0].data) // return one response
})
In here response can be either data1.Json or data2.json. That's the downfall of using this method. Since its return the response of the first executed request, can’t be sure which request response will resolved by the promise. This method useful for bulk requests which you don’t want to see the response of all the requests
Conclusion
Use $q for constructing promises from non-promise Objects/callbacks, and utilize $q.all() and $q.race() to work with existing promises.
I like this question. Because, I too faced this.
This is a service that helps you run functions asynchronously, and use their return values when they are done processing.
Brief Description
Refer example
Promise with $q
Example :
app.service("githubService", function($http, $q) {
var deferred = $q.defer();
this.getAccount = function() {
return $http.get('https://api.github.com/users/haroldrv')
.then(function(response) {
// promise is fulfilled
deferred.resolve(response.data);
// promise is returned
return deferred.promise;
}, function(response) {
// the following line rejects the promise
deferred.reject(response);
// promise is returned
return deferred.promise;
});
};
});

Why do we prefer using $q in angular instead of $http [duplicate]

This question already has answers here:
Why are AngularJS $http success/error methods deprecated? Removed from v1.6?
(2 answers)
Is this a "Deferred Antipattern"?
(3 answers)
Closed 4 years ago.
I am currently using $q service from angular to make API calls like this:
var deferred = $q.defer();
$http.get(config.apiHost + details.url)
.success(function (data) {
deferred.resolve(data);
}).error(function (msg) {
deferred.reject(msg);
});
return deferred.promise;
but we can also use this approach also without using $q:
return $http.get(config.apiHost + details.url)
.success(function (data) {
return data;
}).error(function (msg) {
return msg;
});
and as $http itself returns the promise, I can also use more simplified approach:
$http.get(config.apiHost + 'posts')
.success(function (data) {
console.log(data)
}).error(function (msg) {
console.log(msg);
});
So what is the difference between all these specially between $q and $http, as both returns promise and both are async ? Does angular provides some additional functionality with $q ?
I am not able to find any good answer.
$http uses $q, the first example is redundant, and so is the second. You just need to return the promise that $http.get returns:
return $http.get(config.apiHost + details.url);
The above is the same as your first piece of code.
In addition, return msg is not the same as deferred.reject(msg). The equivalent would be throw msg or return $q.reject(msg)
Another thing to note is that success and error are non-standard, you want to use then and catch.
$q is mainly only used for compatibility with libraries that don't support promises by default and when you can't rely on a native implementation of Promise (for example - in older browsers like IE9). There's no reason (for you) to use it otherwise. An example would if you wanted to make a promise-based $timeout. $http itself uses $q under the hood for these exact reasons.
Unlike what other (since deleted) answers have suggested, you do not need to use $q in order to "store" the result of the $http promise. I would not recommend storing the promise at all (as this tends to lead to spaghetti code), but if you must absolutely do this, you can just store the resultant promise from $http; promises only ever execute once.
Any functions passed to then after a promise has resolved/rejected will be resolved on the next tick, without re-invoking the original action that created the promise in the first place - IOW, the result of the promise is memoized within that object.
Also note that promises chain, which is abit out of scope for this answer, but it essentially means that the following pieces of code are equivalent
function legacyGet() {
const deferred = $q.defer()
$http.get('http://www.google.com')
.then((response) => deferred.resolve(Object.assign(response, {foo: bar}))
.catch((error) => deferred.reject(error))
return deferred.defer
}
function modernGet() {
return $http.get('http://www.google.com')
.then((response) => Object.assign(response, {foo: bar}))
}
To summarise: Your title is wrong. We don't prefer using $q, we only use it sparingly. Prefer to use an ES6 Promise unless you need to support browsers that don't have it and you can't use a polyfill.
In angular mostly all the services returns promises only, but there are some instances where you would like to create your own deferred object using $q.
Case 1
When you are using a library which does not support promise or you have created your own function and want to return a promise.
Case 2
When you are using any construct which by default returns a promise but you want to return a separate promise based on some on some condition.
Example: In angular $http returns a promise only but now if you want that if the response of this promise contains a particular value then only you want to return resolved else return failure then you need to create your own deffered object and need to resolve or fail it based on the value returned by $http response.

angularjs simple .then or $q service in async requests

I don't know what is the exactly difference between AngularJS $q service and simply using .then() after async request.
Simple example with .then() :
function InboxService($http) {
this.getEmails = function getEmails() {
return $http.get('/emails');
};
}
And when using the service (just part of code):
InboxService.getEmails()
.then(function (response) {
// use response
});
What is the difference with $q service with resolve and reject ?
What is the difference with $q service with resolve and reject ?
I assume you are asking about the usage of var deferred = $q.defer() with subsequent deferred.resolve() or deferred.reject()? In this case, the answer is that you don't need it since you already have a promise object returned by $http service. In fact, manually constructing another new promise with $q is not recommended and considered an anti-pattern.
In cases where you work with asynchronous functions (timeouts, ajax-requests) that are not already wrapped into promise, then this is a case when you might want to use $q to create and return promise. But once again, in your case you don't need it as $http service constructs promise for you and one more is simply redundant.
The $q is superfluous and in most cases is not needed. http://www.codelord.net/2015/09/24/$q-dot-defer-youre-doing-it-wrong/

Multiple HTTP requests in Angular

So this my controller:
app.controller('dbCtrl', function($scope, $http) {
$http.get("http://private-abc.apiary-mock.com/bus")
.success(function(response) {
$scope.network = response.networkupdates;});
});
What I wanted to do next is call a 2nd HTTP request, I guess in terms of best practice would it be best to create a 2nd controller to call the 2nd HTTP or would it be best to include the 2nd HTTP call in this current controller (and if so, how?)
Thanks.
So one of the cool aspects of using promises is that they can be chained. So in your case, you are calling:
$http.get("http://private-abc.apiary-mock.com/bus")
Which returns a promise that you can then chain to another promise like so:
var requests = $http.get("http://private-abc.apiary-mock.com/bus").then(function(response) {
$scope.network = response.networkupdates;
// make second get call and return it to chain the promises
return $http.get("some-other-endpoint").then(function(otherResponse) {
// you can do something here with the response data
return otherResponse;
});
});
What you have now is two chained promises that will return the final value, so if you call this later:
requests.then(function(otherResponse) {
// or you can do something here
doSomething(otherResponse);
});
As far as best practices for Angular, I would say you are better off creating a service or factory to handle any and all http requests. Controllers are really just meant to bind data to the view; services are where your business logic and data population should happen.
You can make your $http calls in the same controller.
The $http service is a function which takes a single argument — a configuration object — that is used to generate an HTTP request and returns a promise with two $http specific methods: success and error. It internally uses $q (a promise/deferred implementation inspired by Kris Kowal's Q).
If your two $http are independent of each other you use the $q.all to "join" the results of your http calls.
Example :
$q.all([
$http.get("http://private-abc.apiary-mock.com/bus"),
$http.get('/someUrl')
]).then(function(results) {
$scope.network = results[0];
$scope.whatevername= results[1]
});
}
If your http calls are dependent on one another then you can use the concept of chaining.
for example:
$http.get("http://private-abc.apiary-mock.com/bus").then(function(result) {
$scope.network = result.networkupdates;
return $http.get("someurl").then(function(res) {
return res;
});
});
For refernce of q you can see https://github.com/kriskowal/q
For refernce of $q service you can see https://docs.angularjs.org/api/ng/service/$q

Angularjs $http.get in a factory doesn't return valid JSON but a different object

When I call $http.get from a factory it doesn't return the JSON object I need but a different one.
Here's my code:
var cart = angular.module('cart', []);
cart.factory('getItems',['$http', function($http){
return{
get:$http.get('index.php').
success(function(data){
return data;
})
}
}]);
cart.controller("TableCtrl", ['$scope', 'getItems', function($scope, getItems){
console.log(getItems.get);
}]);
now this is the JSON object that it should return:
[{"id":"1","name":"Cap"},{"id":"2","name":"Coat"},{"id":"3","name":"Shoes"}]
And this is what I get when I console.log
d {$$state: Object, success: function, error: function, then: function, catch: function…}
everything runs fine if I run the $http.get inside the controller, but if I place it in a factory it just doesn't.
It's returning a promise, which you need to resolve
In your controller..
getItems.get().then(function(response) {
console.log(response.data)
});
More information, see The Promise Api
Angular $q docs
$http.get returns a promise not the data itself. Your current use of the success function is not going to get data back.
In your factory:
return{ get: $http.get('myurl')};
Then consuming it should be:
myFactory.get().success(response){
var mydata = response.data;
}
Success is just an addition to the promise. I like to just use .then like standard, unadorned promises.
When I first heard about promises, I thought it meant you could use it without having to provide any sort of callback-like code on your consuming end. That is not true, but promises are still super awesome and very powerful. The coolest thing is that you can keep a promise around, and anybody can add a .then to the promise. Whoever does will get their code executed as soon as the asynchronous request finishes, or right away if it has already finished. So promises let you not have to worry about asynchronous behavior, but you still have to use what is basically its more powerful version of callbacks.

Categories

Resources