Rectangular addResponseInterceptor data object undefined while has it in response object - angularjs

Using Restangular, the get method/promise resolves but the result handed to .then() is empty...with console.log(data); showing undefined. I checked the network tab in chromium debug and the xhr request is good with 200 success...there is a full json response in the body.
Using addResponseInterceptor, I have found that the data argument is undefined, but the response argument shows the object containing the data property with the payload/body.
So, I am left scratching my head.....why is the data argument undefined while the response object properly contains the json payload/response in the response.data?
I need to resolve this so the result is passed to .then() on resolve.
createNode: function(node) {
var account = "9936";
var eventId = "0fd6afd9-4aa0-a5c9-ff0b3e60cdcf";
Restangular.addResponseInterceptor(function(data, operation, what, url, response, deferred) {
console.log("````````````````");
console.log(data);
console.log(operation);
console.log(what);
console.log(url);
console.log(response);
console.log(deferred);
console.log("````````````````");
});
node.js:12
undefined node.js:13
get node.js:14
event node.js:15
/1.0/loadbalancers/account/9936/event/0fd6afd9-4aa0-a5c9-ff0b3e60cdcf node.js:16
^Object {data: Object, status: 200, headers: function, config: Object}
config: Object
data: Object
Automation: Object
Classification: Array[2]
ExecutionTimestamp: "2014-08-13T16:08:37.4676Z"
ID: "0fd6afd9-a5c9-ff0b3e60cdcf"
Incident: Object
LastStatus: "ENQUEUED"
Metadata: Object
Name: "Node Create"
RecordLogs: false
Source: "Device Lifecycle"
Stream: Object
Targets: Array[1]

Make sure all your response interceptors return the data at the end:
Restangular.addResponseInterceptor(function(data, operation, what, url, response, deferred) {
// your code here
return data;
});
Not returning anything will set the data to undefined on following response interceptors calls.

Related

$resource:badcfg Error in resource configuration for action `query`. Expected response to contain an object but got an array

I have following Service, the query always returns an array.
.factory('ClosingDocService', ['$resource', function ($resource) {
return $resource("http://localhost:5001/api/ClosingDoc/:id",
{ id: "#id" },
{
'query': { method: 'GET' },
'save': { method: 'POST', transformRequest: angular.identity, headers: { 'Content-Type': undefined } }
});
}])
However, the following call always got the error?
ClosingDocService.query({ category: model.category }).$promise
.then(function (x) { });
Using fiddler shows the following correct url has been called and the values were returned.
http://localhost:5001/api/ClosingDoc?category=XXX
Error:
angular.js:13920 Error: [$resource:badcfg] Error in resource configuration for action query. Expected response to contain an object but got an array
I found a solution - adding isArray: true. But why?
'query': { method: 'GET', isArray: true },
This occurs due to how $resource object methods are handled.
From the docs on $resource:
It is important to realize that invoking a $resource object method immediately returns an empty reference (object or array depending on isArray). Once the data is returned from the server the existing reference is populated with the actual data. This is a useful trick since usually the resource is assigned to a model which is then rendered by the view. Having an empty object results in no rendering, once the data arrives from the server then the object is populated with the data and the view automatically re-renders itself showing the new data. This means that in most cases one never has to write a callback function for the action methods.
Essentially, unless you provide isArray: true, the $resource object method pre-allocates an Object for the data that is to be returned. When the data being returned actually ends up being an array, that data can't be populated into the pre-allocated object.
I had the same issue too. What worked for me was the following fix
Changing the query to get as follows:
ClosingDocService.get({ category: model.category }).$promise
.then(function (x) { });

AngularJS ngResource and IE9 issue: response.data is undefined in the error callback function

ISSUE: In IE9, when I call $resource.save, I get undefined on response.data inside the error callback function. In chrome, response.data has the "errors" JSON object returned from the server.
Here is the $resource call:
TicketResource.save(inputParams, function (data) {
//the data object is same on both browsers
}, function (response) {//called when server returns status 422
//IE9: response.data is undefined
//Chrome: response.data contains the server returned JSON object
});
In IE9 developer tools, "statusText" on the response object has this error
statusText: "IOError [IOErrorEvent type=\"ioError\" bubbles=false cancelable=false eventPhase=2 text=\"Error #: [IOErrorEvent type=\"ioError\" bubbles=false cancelable=false eventPhase=2 text=\"Error #2032"
Note: In my app, no custom responseInterceptors are defined on $httpProvider
Appreciate any inputs on this issue!

AngularJS $http POST request different results with then and success

Something is driving me nuts; maybe someone can help me out with the following? :
I am using AngularJS 1.2.26 (have to because IE8 needs to be supported)
I have to invoke some backend services that were initially build for a backbone frontend. I managed to do that in the following way:
$http({
method: 'POST',
url: url,
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
transformRequest: this._transformRequest,
data: formData
})
.success(function (data) {
// bla bla not relevant
}).error(function (error) {
// bla bla not relevant
});
Now i try to work with the then function as i find that more consequent, so i change the code into:
$http({
method: 'POST',
url: url,
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
transformRequest: this._transformRequest,
data: formData
}).then(
function (response) {
// not relevant
}, function (error) {
// not relevant
});
According to me, in theory this should have the same result as the initial implementation, however to my surprise the request now fails on the server. While debugging I noticed that the result of the transform request function delivers a very different result in both scenario's in the request that is handled with success and error the result of transform request is as follows:
com.bank.token.session=XXXXX&model=%7B%22relatieRol%22%3A%22AANVRAGER%22%2C%22evaUitgevoerdDat%22%3Anull%2C%22sfhUitgevoerdDat%22%3Anull%2C%22bkrUitgevoerdDat%22%3Anull%2C%22bkrBekendCd%22%3A%22GOED_BEKEND%22%7D
When i use the 'then' function as the way to handle the result the transformRequest function returns the following (wrong) result:
com.bank.token.session=XXXXXXXXXXX&model=%7B%22data%22%3A%7B%22relatieRol%22%3A%22AANVRAGER%22%2C%22evaUitgevoerdDat%22%3Anull%2C%22sfhUitgevoerdDat%22%3Anull%2C%22bkrUitgevoerdDat%22%3Anull%7D%2C%22status%22%3A200%2C%22config%22%3A%7B%22method%22%3A%22POST%22%2C%22transformResponse%22%3A%5Bnull%5D%2C%22url%22%3A%22http%3A%2F%2Flocalhost%2Femployee%2Findex.html%2Ffoo-web%2Fxchannel-foo-secure-portlet%2F1598792178%2Fver%3D2.0%2Fresource%2Fid%3Dfoo-fetch-%2Frparam%3Dportal%3DfooPortal.wsp%22%2C%22headers%22%3A%7B%22Content-Type%22%3A%22application%2Fx-www-form-urlencoded%22%2C%22Accept%22%3A%22application%2Fjson%2C%20text%2Fplain%2C%20*%2F*%22%7D%2C%22data%22%3A%7B%22com.bank.token.session%22%3A%22XXXXXXXXXX%22%2C%22model%22%3A%22%7B%5C%22relatieRol%5C%22%3A%5C%22AANVRAGER%5C%22%7D%22%7D%7D%2C%22statusText%22%3A%22OK%22%2C%22bkrBekendCd%22%3A%22GOED_BEKEND%22%7D
This really surprises me; how can the handler on the $http service influence the way the request is handled? I would like to use 'then' for handling my $http POST; but it seems not to work. Anybody knows why? Many thanks in advance!
my transformRequest function looks like this:
_transformRequest: function (obj) {
var str = [];
for (var p in obj) {
if (obj.hasOwnProperty(p)) {
str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
}
}
console.log('transform: ', str.join("&"));
return str.join("&");
}
success and error unpack the data property of the response for you (as well as route to the pretty names). So, if you change to then you need to manually address the data property of the response in order to get the same information:
$http({
method: 'POST',
url: url,
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
transformRequest: this._transformRequest,
data: formData
}).then(
function (response) {
var data = response.data;
// not relevant
}, function (error) {
var data = error.data;
// not relevant
});
Here is the relevant part in the $http documentation:
Returns a promise object with the standard then method and two http
specific methods: success and error. The then method takes two
arguments a success and an error callback which will be called with a
response object. The success and error methods take a single argument
- a function that will be called when the request succeeds or fails respectively. The arguments passed into these functions are
destructured representation of the response object passed into the
then method. 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 $http legacy promise methods success and error have been deprecated. Use the standard then method instead.1

Extract data from $resource.get(...).$promise

I use $resource to get data from Facebook's Graph api:
resource = $resource(
"https://graph.facebook.com/v2.2/:api/:id/:node/"
)
So for instance, I made a successful request to 'https://graph.facebook.com/v2.2/user.id/albums/' by:
resource.get({id:user_id, node: "albums", access_token: ....}).then(function(response)
{
console.log(response)
})
and the response shows (in Chrome dev tool console):
Resource
- $promise: Promise
- $resolved: true
- data: Array[9]
- 0: Object
- 1: Object2:
- length: 9
- __proto__: Array[0]
- paging: Object
- __proto__: Resource
So I naively try to add under console.log response another console.log response.data,
but it shows 'undefined'.
So I wonder how to extract the data object?
========================== EDIT ========================
It seems the reason being
resource.get({id:user_id, node: "albums", access_token: ....}).then(function(response)
{
console.log(response)
})
is chained after another resource request as follows:
FB.get_user().then(function(response) {
var user_id;
return user_id = response.id;
}).then(function(response) {
return self.albums = FB.resource.get({
id: user_id,
node: "albums",
access_token: Auth.get_user().social_account_access_token
});
}).then(function(response) {
console.log("response", response); # Log #1
return console.log("response.data", response.data); # Log #2
});
In this case Log #1 will log out the resource object with data being an array, while Log #2 gives undefined.
If I do not chain the then function, but put the last one inside the previous .then, I have the expected results:
FB.get_user().then(function(response) {
var user_id;
return user_id = response.id;
}).then(function(response) {
return self.albums = FB.resource.get({
id: user_id,
node: "albums",
access_token: Auth.get_user().social_account_access_token
}).$promise.then(function(response) {
console.log("A: response", response); # Log #1
return console.log("response.data", response.data); # Log #2
});
});
gives Log #1 the same result, while Log #2 is an array of 9 elements.
** So I wonder I is the problem of the original method?**
What's happening in your first attempt is that in your second then() you are returning the return value of FB.resource.get(), but this value is not a promise, so this then() resolves immediately, and processing moves on to the next then() before the data is done being retrieved. When you view the values in your Chrome debugger, you are stopping the execution long enough for the request to finish, and the data is populated when you observe it. (There is a term for this phenomenon, by the way.)
According to the notes on this pull request and this note in the developer's guide, you should be using instance.$promise if you want to chain off of a resource request. So your second approach that uses $promise is more or less the correct way to go about it.
Your code can be cleaned up a bit. Unless you have a reason to want a separate step to extract the FB user id and pass it to the next step, you can remove the first .then(). There is some other tidying up that you can do as well:
FB.get_user()
.then(function (response) {
var user_id = response.id;
// the value assigned to self.albums here is a (mostly) empty object that will
// be populated with data when the request finishes
self.albums = FB.resource.get({
id: user_id,
node: "albums",
access_token: Auth.get_user().social_account_access_token
});
return self.albums.$promise;
})
.then(function (response) {
// (avoid putting a [then] inside another [then] unless you need to)
console.log("A: response", response);
console.log("response.data", response.data);
return response.data;
});

parseJSON(response) is null

I have a Backbone model that is making a successful server request. The callback is using backbone's trigger method to trigger an event in the associated view, and its passing the parsed json response from the server request as the second parameter of the trigger method, as described in the backbone documents. In the view, the event triggers the render method, but the response object is null in the view. It's throwing this error
Uncaught TypeError: Cannot read property 'word' of null
Can anyone see what I might be doing wrong?
The server request from the model
new: function() {
var _this = this;
console.log("new function of model");
$.ajax({
url: "/gamestart",
type: "GET",
success: function(response) {
console.log(response);
var json = $.parseJSON(response);
_this.set({lost: false});
_this.set({win: false});
_this.trigger("gameStartedEvent", json);
}
})
},
the event in the initializer method of the view which triggers the render method to render the response
this.model.on("gameStartedEvent", this.render, this);
the render method where the response is null
render: function(response) {
$("#hint").show();
console.log(response);
var html = this.template({characters: response.word});
this.el.hide();
this.el.html(html).show();
},
Note, if it matters, the view is being instantiated with the model
var word_view = new WordView({model: game})
Update
Actually the error's happening here. The response is returning successfully but i'm parsing it incorrectly. The variable json is null when I check the console. Can you see what I'm doing wrong?
var json = $.parseJSON(response);
console.log(json)
Response
Object {word: Array[6]}
word: Array[6]
__proto__: Object
There was actually no need to call parseJSON on the response object. I could get the word property directly off the response object, so I just passed the response object as the second argument to trigger, and called response.word in the view.
$.ajax({
url: "/gamestart",
type: "GET",
success: function(response) {
console.log(response.word);
var json = $.parseJSON(response); ####unnecessary to parseJSON here
console.log(json);
_this.set({lost: false});
_this.set({win: false});
_this.trigger("gameStartedEvent", response);
}
})
},

Resources