Trouble with Angular .then() response data - angularjs

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');
});

Related

How does AngularJS get the values for data, status, etc in function parameter?

Sorry this may be a dumb question but it isn't obvious to me:
function login(email, password){
return $http.post('/api/v1/login/', {
email: email,
password: password
}).then(loginSuccessFn, loginErrorfn);
function loginSuccessFn(data, status, headers, config){
Authentication.setAuthenticatedAccount(data.data);
window.location = '/'
}
function loginErrorFn(data, status, headers, config) {
console.error('Failed');
console.log(data)
}
}
This is a snippet from a tutorial I'm doing, If I need to post more I will.
In the line function loginSuccessFn(data, status, headers, config) where is the function getting the data, status, headers, and config values from? console.log(data) works, I'm just not sure where 'data' is being used anywhere else
Short answer:
Those are properties of response object of returned promise from your http call.
Details:
HTTP request returns a promise that contains a response object. The response object not only contains the properties that you mentioned in your question but according to the angular documentation also has statusText and xhrStatus properties. Below you can find expalanation of each property copied from the angular documentation.
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.
xhrStatus – {string} – Status of the XMLHttpRequest (complete, error, timeout or abort).
You can find more information about this subject in the following page.
https://docs.angularjs.org/api/ng/service/$http

How to Wait for Multiple Promises for All Data Success Callbacks

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...

AngularJS then() behaves differently than success()-error() [duplicate]

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.

How to use .then like .success?

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(){})

ngResource transformResponse doesn't seem to be transforming the response

I made a base class, HttpService:
class HttpService
constructor: (url) ->
#service = $resource url, {}, #actionOptions()
actionOptions: ->
query:
method: 'GET'
isArray: true
transformResponse: (data) =>
response = []
wrapped = angular.fromJson(data)
angular.forEach wrapped[#indexRoot], (item) =>
response.push #jsonToModel(item)
response
I inherit like this:
class FooService extends HttpService
constructor: ->
super '/api/foos/:id'
#indexRoot = 'foos'
all: ->
#service.query()
jsonToModel: (data) ->
new Foo(data)
In general, the idea is to extend HttpService providing the URL of the resource and the index root (JSON has a root element for the index action). I override jsonToModel to provide a way to transform each JSON element in the response into a custom object, in this case Foo.
When debugging, I can see that response is what it should be in actionOptions(), so it seems like transformResponse is returning what I expect, an array of Foos.
Whenever I call FooService.all() though, I get an array of Resources (ngResource default)... anyone have any idea what I'm doing wrong? I've omitted the dependency injection and everything, but it's all working and I have no errors in console.
The $resource service wraps the response in Resource objects using an interceptor, which occurs after the transformResponse, so while transformResponse is a good place to unwrap a root object (the results from there get fed into the interceptors), you will also need an interceptor to call your jsonToModel function.
The relevant docs:
https://docs.angularjs.org/api/ngResource/service/$resource
transformResponse – {function(data, headersGetter)|Array.} – transform function or an array of such functions. The transform function takes the http response body and headers and returns its transformed (typically deserialized) version. By default, transformResponse will contain one function that checks if the response looks like a JSON string and deserializes it using angular.fromJson. To prevent this behavior, set transformResponse to an empty array: transformResponse: []
interceptor - {Object=} - The interceptor object has two optional methods - response and responseError. Both response and responseError interceptors get called with http response object. See $http interceptors.

Resources