How to use $http promise response outside success handler - angularjs

$scope.tempObject = {};
$http({
method: 'GET',
url: '/myRestUrl'
}).then(function successCallback(response) {
$scope.tempObject = response
console.log("Temp Object in successCallback ", $scope.tempObject);
}, function errorCallback(response) {
});
console.log("Temp Object outside $http ", $scope.tempObject);
I am getting response in successCallback but
not getting $scope.tempObject outside $http. its showing undefined.
How to access response or $scope.tempObject after $http

But if I want to use $scope.tempObject after callback so how can I use it. ?
You need to chain from the httpPromise. Save the httpPromise and return the value to the onFullfilled handler function.
//save httpPromise for chaining
var httpPromise = $http({
method: 'GET',
url: '/myRestUrl'
}).then(function onFulfilledHandler(response) {
$scope.tempObject = response
console.log("Temp Object in successCallback ", $scope.tempObject);
//return object for chaining
return $scope.tempObject;
});
Then outside you chain from the httpPromise.
httpPromise.then (function (tempObject) {
console.log("Temp Object outside $http ", tempObject);
});
For more information, see AngularJS $q Service API Reference -- chaining 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.1
Explaination of Promise-Based Asynchronous Operations
console.log("Part1");
console.log("Part2");
var promise = $http.get(url);
promise.then(function successHandler(response){
console.log("Part3");
});
console.log("Part4");
The console log for "Part4" doesn't have to wait for the data to come back from the server. It executes immediately after the XHR starts. The console log for "Part3" is inside a success handler function that is held by the $q service and invoked after data has arrived from the server and the XHR completes.
Demo
console.log("Part 1");
console.log("Part 2");
var promise = new Promise(r=>r());
promise.then(function() {
console.log("Part 3");
});
console.log("Part *4*");
Additional Resources
Angular execution order with $q
What is the explicit promise construction antipattern and how do I avoid it?
Why are angular $http success/error methods deprecated? Removed from v1.6?
How is javascript asynchronous AND single threaded?
Ninja Squad -- Traps, anti-patterns and tips about AngularJS promisesGood theory but needs to be updated to use .then and .catch methods.
You're Missing the Point of Promises

$http call is async call. The callback function executes when it has returned a response. Meanwhile the rest of the function keeps executing and logs $scope.tempObject as {}.
When the $http is resolved then only $scope.tempObject is set.
Angular will bind the changed value automatically using two way binding.
{{tempObject}} in the view will update itself.
if you want to use tempObject after callback then do this
then(function(data){
onSuccess(data);
},function(){
});
function onSuccess(data){
// do something
}

Try to use a $scope.$apply before to finish the successCallback function. An other solution is to change successCallback -> function so:
$http({ method: 'GET', url: '/myRestUrl' }).then(function(success) { $scope.tempObject = success; console.log("Temp Object in successCallback ", $scope.tempObject); }, function(error) { });

Related

Ensuring all Api's has been loaded in a page in AngularJS

I have 4 controllers in a page in AngularJS. Each controller calls Api's via http request(scope $http). I want to ensure that all the Api's has been called and loaded till then I can show the loading gif image. How to check all the Api's has been loaded in the page in AngulaJS.
I am not sharing the exact code some variable and name I have modified.
myApp.controller('testController',function ($scope, $http, $q, $filter) {
var _promises = {};
_promises['abc'] =
$http({
url: API_URL+'abc-type/',
method: 'GET',
params: {'test1': 'test2'}
});
_promises['abc1'] =
$http({
url: API_URL+'abc-type2/',
method: 'GET'
});
}
$q.all(_promises).then(function (res) {
alert("All promises executed.");
});
});
$http uses promises ($q) for it's API. You can use the $q.all method to run a callback when an array of $http requests are resolved (you will need to make sure all service requests return promises to avoid undefined behavior).
Combines multiple promises into a single promise that is resolved when all of the input promises are resolved.
It would look something like this
$scope.showLoadingGif = true;
$q.all([MyService.makeGet(), MyService.makeAnotherGet(), ...]).then(function(responses) {
// all the calls have returned a response by this point
$scope.showLoadingGif = false;
})

What does $q.defer() in following code in angularjs context

What is the use of $q.defer() in following code. I am bit confused or not able to understand the use of $q or defer?
service.serviceCall = function (methodName, params) {
var deferred = $q.defer();
$http({ method: "POST", url: url + methodName, data: params, headers: headers }).success(function (result) {
deferred.resolve(result);
}).error(function (result) {
deferred.reject(result);
});
return deferred.promise;
}
service.serviceCal("POST", {"param1":"value1"}).then(function(data){
//here data will be object which is resolved in success call
}).fail(function(){
//here data will be object which is rejected in failure call
})
This are promises, we user $q.defer() to return a promise using defer.promise(). It is contract between the calling object and promise that in future the calling object (here then and fail) will ultimately get a value either in then or fail depends whether it is resolved or rejected.
Read about promises here: Promises
Go through docs of $q module: $q Module Angular
A service that helps you run functions asynchronously, and use their
return values (or exceptions) when they are done processing.
So promises are used in async programming. $q is Angular's implementation of promises.
Usage of the above function:
service.serviceCal(methodName, params)
.then(function(resolve){
// on successful resolving
// called when defer.resolve is called
// resolved object: resolve
}, function(reject){
// on reject
// called when defer.reject is called
// rejected object: reject
})
The code is using deprecated methods on the result of calling $http. Although $http returns a promise it has some additional methods .success and .error that don't quite work within the usual promise structure.
$q.defer() creates a promise which is returned from the function and this code uses success and error to resolve the promise. A simpler way to write this code would be to just use the promises returned by $http and its .then method.
service.serviceCall = function (methodName, params) {
return $http({ method: "POST", url: url + methodName, data: params, headers: headers })
.then(function successFn (response) {
return response.data;
});
}
This has the same effect as the original code: it returns a promise which either resolves to the data from the response, or if an error occurs the promise is rejected.

angularjs http service wait for data

I have HTTP service that returns promise to inspection2update.DamageTypeId property and continue to execute further.
HTTP service:
function post(objectTypeId, damageDescription) {
var defer = $q.defer();
$http.post(serviceAddress + "save/" + objectTypeId + "/" + damageDescription).then(function (response) {
defer.resolve(response.data);
});
return defer.promise;
}
Here how I call service in controller:
inspection2update.DamageTypeId = damageTypesService.save(inspection2update.ObjectTypeId, self.dType);
But I need to wait until I get data from service and only after it, to execute further.
For this purpose I use $q service inside $http resolver, but still I get promise from my service and no data.
What do I have to change in my code to make service wait for data?
You are returning a promise which is resolved after the http call has finished fetching the data. The consumer who use this service needs to wait for the promise to resolve and then do something with the data.
Use the then syntax to receive the promise data and execute further:
damageTypesService.save(inspection2update.ObjectTypeId, self.dType).then(function(data) {
inspection2update.DamageTypeId = data;
// rest of execution...
});
P.S - as far as I can see there is no use of $q in your case (unless you want to mingle with the data / make logs, etc...). You can return the $http call as is:
function save(objectTypeId, damageDescription) {
return $http.post(serviceAddress + "save/" + objectTypeId + "/" + damageDescription);
}
Use the best of angular promise with $q
function save (objectTypeId, damageDescription) {
var deferred = $q.defer();
$http({
url: serviceAddress + "save/" + objectTypeId + "/" ,
method: 'POST',
data: damageDescription
})
.success(function (data) {
deferred.resolve(data);
})
.error(function (data) {
deferred.resolve(data);
});
return deferred.promise;
}
And in your controller use .then function
damageTypesService.save(inspection2update.ObjectTypeId, self.dType).then(function(response){
/*use the response here
eg: inspection2update.DamageTypeId = response.id
*/
})
First off, you have your service method named post and your are calling a method called save. Is that an mistake? Second, I don't see any reason you should be using the $http service it is low level and your request is simple. You should checkout $resource it provides a higher level of abstraction and will work for straightforward requests like yours. Now, onto your problem. both $http and $resource always return a promise. so, typically in your service or controller you provide a callback that takes the response received from the request and processes it. Since the approach for $resource and $http are similar, but you asked about $http I will show you using $http.
function post(objectTypeId, damageDescription) {
return $http.post(serviceAddress + "save/" + objectTypeId + "/" + damageDescription);
}
Now, in your controller you call the service method post() like this.
damageTypesService.post(inspection2update.ObjectTypeId, self.dType).then(mycallback);
function myCallback(response){
inspection2update.DamageTypeId = response; // DamageTypeId now won't be populated until the request is resolved.
}

Does Angular1.4 $http include a promise already in the http get? Or do I make my own

I'm a bit confused, the more I read resources online about $q and $http the more my head spins. So if I do a $http.get call does that not include a promise? Or do I bring $q in?
It is built on $q and returns a promise. See the docs: https://docs.angularjs.org/api/ng/service/$http
And the example there:
$http({
method: 'GET',
url: '/someUrl'
}).then(function successCallback(response) {
// this callback will be called asynchronously
// when the response is available
}, function errorCallback(response) {
// called asynchronously if an error occurs
// or server returns response with an error status.
});
$http.get is just a convenience method on the above.
You can refer to the following link
https://www.peterbe.com/plog/promises-with-$http
This service ($http.get()) will return promise as success callback and error callback...so this function itself returns promise. You just have to handle it
The $http API is based on the deferred/promise APIs exposed by the $q
service. While for simple usage patterns this doesn't matter much, for
advanced usage it is important to familiarize yourself with these APIs
and the guarantees they provide.
https://docs.angularjs.org/api/ng/service/$http
Meaning that the $http.get will return a promise anyway. No need nesting your own $q approach. Just return the $http invoke.
$http.get call does that not include a promise? The Answer is Yes, you can return a promise or resolve the promise with $http
Returning a promise from $http.get
getData: function() {
return $http.get('some url'); // you can resolve this promise later
// using (then)
}
So later in your code you can resolve the above promise like this
...
myService.getData().then(function(response) {
// do something with response
}).catch()
Resolve the promise inline
getData: function() {
$http.get('some url').then(function(response) {
// do something with response
}).catch()
}

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