This question already has answers here:
Why are AngularJS $http success/error methods deprecated? Removed from v1.6?
(2 answers)
Closed 4 years ago.
As the success() and error() functions are deprecated in AngularJS, I am updating my codes, replacing them with then(). Now according to my understanding, these two pieces of codes should behave identically:
$http
.get(/* some params */)
.success(function() {
// success cases here
})
.error(function() {
// error cases here
});
And
$http
.get(/* some params */)
.then(function() {
// success cases here
}, function() {
// error cases here
});
But in some cases I am getting different behavior. Can you please explain to me why would that happen, and more importantly, what would be the way to guarantee the identical behavior using then() functions?
The .success and .error methods ignore return values.
Consequently they are not suitable for chaining.
var httpPromise = $http
.get(/* some params */)
.success(function onSuccess(data, status, headers, config) {
var modifiedData = doModify(data);
//return value ignored
return modifiedData;
})
.error(function onError(data, status, headers, config) {
// error cases here
});
httpPromise.then(function onFullfilled(response) {
//chained data lost
//instead there is a response object
console.log(response.data); //original data
console.log(response.status); //original status
});
On the otherhand, the .then and .catch methods return a derived promise suitable for chaining from returned (or throw) values or from a new promise.
var derivedPromise = $http
.get(/* some params */)
.then(function onFulfilled(response) {
console.log(response.data); //original data
console.log(response.status); //original status
var modifiedData = doModify(response.data);
//return a value for chaining
return modifiedData;
})
.catch(function onRejected(response) {
// error cases here
});
derivedPromise.then(function onFullfilled(modifiedData) {
//data from chaining
console.log(modifiedData);
});
Response Object vs Four Arguments
Also notice that the $http service provides four arguments (data, status, headers, config) when it invokes the function provided to the .success and .error methods.
The $q service only provides one argument (response) to the functions provided to the .then or .catch methods. In the case of promises created by the $http service the response object has these properties:1
data – {string|Object} – The response body transformed with the transform functions.
status – {number} – HTTP status code of the response.
headers – {function([headerName])} – Header getter function.
config – {Object} – The configuration object that was used to generate the request.
statusText – {string} – HTTP status text of the response.
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.2
Update
The .success and .error methods have been deprecated and removed from AngularJS V1.6.
For more information, see
Why are angular $http success/error methods deprecated? Removed from v1.6?.
One important difference is that you should probably use .then().catch() instead of .then(function(), function()). [1] The two-argument then (where the second function is the error handler) does not capture errors in the first function, as I understand it. IOW: $http.get().then(a, b) will not call b() if a() throws an error, where as $http.get().then(a).catch(b) will.
What other sorts of different behaviors are you getting?
1: standardized Promise API - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
The success function and the promise callback indeed receive different objects. As described in the docs, the promise callback receives a response object containing status, headers, data etc. The success function returns just the data field (the response body) of that object.
Related
I'm a newbie to Angular JS. I was referring Online tutorials and came across the $http service.
(function () {
"use strict";
angular
.module("ngClassifieds") // referring module which is already created
.controller("classifiedsCtrl", function ($scope, $http) {
$http.get('data/classifieds.json')
.then(function(classifieds){
$scope.classifieds = classifieds.data;
})
});
})();
In this piece of code, I'm not able to figure out these lines. Can
anyone explain what actually happens here ?
$http.get('data/classifieds.json')
.then(function(classifieds){
$scope.classifieds = classifieds.data;
}
I have this data in my data/classifieds.json file.
My question is, what exactly the data referred in classifieds.data is ?
what does classifieds.data represent here ?
what information does it contain?
what would be the result which we assign to $scope.classifieds?
$http returns a promise, it's an asynchronous call, angular use a fork of a library called Q for promises, you can see $q documentation here: https://docs.angularjs.org/api/ng/service/$q.
When the promise is fulfilled, that means, the asynchronous call is complete, the .then method call success or error callback depending on the result of the async call.
.then(successCallback, [errorCallback], [notifyCallback]) – regardless
of when the promise was or will be resolved or rejected, then calls
one of the success or error callbacks asynchronously as soon as the
result is available. The callbacks are called with a single argument:
the result or rejection reason. Additionally, the notify callback may
be called zero or more times to provide a progress indication, before
the promise is resolved or rejected.
The argument passed to the success callback is an object with the information about the request response. The data property contain the body of the response, in other way, all the content of data/classifieds.json file (in your case), therefore, $scope.classifieds will contain the json returned by data/classifieds.json.
Here a friendly article about promises and $q: http://www.dwmkerr.com/promises-in-angularjs-the-definitive-guide/
A simple get request example from AngularJS Docs.
$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.
});
In your code,
$http.get('data/classifieds.json') // This is the URI of your json file
.then(function(classifieds){ // Success callback
$scope.classifieds = classifieds.data; // Here, you are assigning response's data into $scope.classifieds
}
I have this API call, but I don't receive the data in my successCallback in the same order as I send it.
for (var i = 0; i < data.length; i++) {
$http.post('/api/bla/blabla', $.param(data[i]))
.then(successCallback, errorCallback);
}
var successCallback = function (response) {
/*
receive data in random order.
assume its being send / handled so fast, thats its random
which gets done first.
*/
};
Can I somehow wait for all data to be received, and then reorder it to the original ordering? or is there another solution.
Use $q.all to get all the data in the right order.
var promiseArray = [];
for (var i = 0; i < data.length; i++) {
var dataPromise = $http.post('/api/bla/blabla', $httpParamSerializer(data[i]))
.then (function (response) {
//return data for chaining
return response.data;
})
;
promiseArray.push(dataPromise);
}
$q.all(promiseArray).then(function (dataArray) {
//dataArray will be in original order
//process results here
}).catch (function (errorResponse) {
//log error
});
The promiseArray will be created in the correct order. Even though the individual XHR POST requests may not be served in the original order, the $q service will track the promises and fill the data array in the correct order (or resolve rejected on the first error).
The DEMO on JSFiddle.
As Groben says, you could create an array of the promises for each request, and then you can use the "when" callback to execute when all are completed.
$http.get('/someUrl', config).then(successCallback, errorCallback);
$http.post('/someUrl', data, config).then(successCallback, errorCallback);
you can try these
note the The response object has these properties:
data – {string|Object} – The response body transformed with the transform functions.
status – {number} – HTTP status code of the response.
headers – {function([headerName])} – Header getter function.
config – {Object} – The configuration object that was used to generate the request.
statusText – {string} – HTTP status text of the response.
And these too can also work depending on the API you working on...
The AngularJS documentation has a Deprecation Notice for the $http success and error methods. Is there a specific reason this abstraction was removed from the library?
The problem was that .success and .error methods are not chainable because they ignore return values. This caused problems for people familiar with chaining and encouraged poor code from people unfamiliar with chaining. Witness all the examples on StackOverflow that use the deferred anti-pattern.
To quote one of the AngularJS team:
IMO .success and .error were a bad bit of API design in the first place. This issue highlights a number of situations where developers get confused because they either expect .success and .error to work the same way as .then or vice versa.
In a perfect world I would rather just ditch these $http specific "promises". Instead we could encourage developers to use the standard $q promise API .then and .catch. There is very little benefit IMO in working with explicit parameters over working with the response object.
— AngularJS Issue #10508 $http .success/.error dissimilar from how .then works.
Deprecation Notice (v1.5)
The $http legacy promise methods success and error have been deprecated. Use the standard then method instead. If $httpProvider.useLegacyPromiseExtensions is set to false then these methods will throw $http/legacy error.
— AngularJS $http Service API Reference -- deprecation notice
UPDATE
The deprecated .success and .error methods have been removed from AngularJS 1.6.
Due to b54a39, $http's deprecated custom callback methods - .success() and .error() - have been removed. You can use the standard .then()/.catch() promise methods instead, but note that the method signatures and return values are different.
$http(...)
.then(function onSuccess(response) {
// Handle success
var data = response.data;
var status = response.status;
var statusText = response.statusText;
var headers = response.headers;
var config = response.config;
...
}).catch(function onError(response) {
// Handle error
var data = response.data;
var status = response.status;
var statusText = response.statusText;
var headers = response.headers;
var config = response.config;
...
});
— AngularJS Developer Guide - Migrating to v1.6 - http
The pattern that javascript it using related to promises is only with .then(successCallback, errorCallback), so they are probably aiming to use js pattern.
I have code like this. But thats return OLD token, although my server has NEW token.
function stores() {
return $http.get(URL + 'stores').then(function(response){
console.log(response.config.headers.Authorization);
});
}
This code below return NEW token, as my server last generate. This is what i want.
function stores() {
return $http.get(URL + 'stores').success(function(data, status, headers, config){
console.log(headers('Authorization'));
});
}
The question is, how can i do this with .then method ? i look at $http doc, they said .success will depreceate
Your problem is in the way you're accessing the headers. The response object has the following properties (from Angular docs):
data – {string|Object} – The response body transformed with the transform functions.
status – {number} – HTTP status code of the response.
headers – {function([headerName])} – Header getter function.
config – {Object} – The configuration object that was used to generate the request.
statusText – {string} – HTTP status text of the response.
Access the headers like this:
function stores() {
return $http.get(URL + 'stores').then(function(response){
console.log(response.headers('Authorization'));
});
}
In pretty sure it because .then needs two call back function. One success and one error. Like so:
$http.get( URL + 'stores').then(function(res){
$scope.var = res.data;
},function(){})
I have an angular app that's using a promise to fetch an array in a factory but I don't understand how to work with the .then argument. What exactly is response and how can I access the data within it? How would I say something like response.objectProperty? Why won't console.log() work in here?
myArray.getArrayObjects(objectProperty).then(function (response) {
$scope.model = response;
console.log('Cannot test');
}
From the documentation:
The response object has these properties:
data – {string|Object} – The response body transformed with the transform functions.
status – {number} – HTTP status code of the response.
headers – {function([headerName])} – Header getter function.
config – {Object} – The configuration object that was used to generate the request.
statusText – {string} – HTTP status text of the response.
The .data property corresponds to what would be passed in as the first argument to a success() handler, so what you want is:
myArray.getArrayObjects(objectProperty).then(function (response) {
$scope.model = response.data.objectProperty;
console.log('Cannot test');
});