transform request data with resource service in angular - javascript

I'm trying to send just the array of my data to the server. I found this post discussing how to send an array, but I can't get it to work.
AngularJS: ngResource and array of object as params to URL
The problem I am having is my resource gets sent back to me as JSON like this
{
Results: []
}
So when I ask for my resources,
var collaboratorResource = api.CollaboratorList.get({Id: Id });
but then, if I try something like
collaboratorResource.$save($scope.collaborators);
When I look at firebug, it shows that my data is being sent as
{
Results: []
}
when in reality, I don't want to send the data as an object with the array as a Results property. I want to send it just as an array []. I need to do that since the api is legacy and expects that.
I've been trying to see if transformRequest works, like if I did
collaboratorResource.$save({data: $scope.collaborators, transformRequest: function (data, headers) { return data.results; }});
collaboratorResource.$save({}, $scope.collaborators);
collaboratorResource.$save($scope.collaborators);
But that doesn't seem to work either. Is this even possible? As an aside, if I use $http like this, it works:
$http({ method: "POST", data: $scope.collaborators, url: collaboratorUrl });
I'm just not sure how to use the $resource service properly since I'd prefer to wrap everything in $resource if possible and not have a hybrid of both if possible. Thanks.

Related

Angular $http attach data as object

I'm trying to get list of tracks from soundcloud API with angularjs.
The parameters i'm trying to send are:
1) client_id (string)
2) duration (object with two properties).
Here's the code:
var CLIENT_ID = 'a81f01ef5d0036415431e8be76c8db0e';
var TRACKS_URL = 'https://api.soundcloud.com/tracks.json';
var app = angular.module('soundcloud', []);
app.controller('tracksController', function ($scope, $http) {
$http({
url: 'https://api.soundcloud.com/tracks.json',
method: 'GET',
data: {
client_id: CLIENT_ID,
duration: { // in milliseconds
from: 300000,
to: 400000
}
}
})
.success(function (data) {
$scope.trackList = data;
})
.error(function () { alert('error'); });
});
These parameters aren't recognized at all when I check the request in the broweser's debugger.
I tried to use 'params' instead of 'data', but this way it turns the 'duration' object to json --> then I get status 500 in response.
When I only send the client_id in params, it works fine because there's no object, only string.
jQuery's ajax method works fine: https://jsfiddle.net/oacwz1up/3/
What should I do ? How can I send the parameters normally ?
Help please! Thanks!
This happens because Angular serializes the request parameters differently than JQuery.
Angular 1.4 will address this problem introducing a paramSerializer property on the $http config object (and on $httpProvider.defaults). This can be used for arbitrarily serializing the requests parameters (for all or a particular request).
Note, that the feature is available only since v1.4.0-rc.0.
Besides the default serializer (which converts objects to JSON strings), there is an additional built-in serializer that emulates JQuery's param(): $httpParamSerializerJQLike.
You can use it like this:
$http.get(<API_URL>, {
params: {...},
paramSerializer: '$httpParamSerializerJQLike'
});
See, also, this short demo.
If you are using an older version of Angular, you could do one of the following:
Construct the whole URL (including the query string) yourself (possibly using an $http request interceptor to automatically apply this to all requests).
Keep the params in a flat format that will result in Angular's serializing them as expected:
var REQ_PARAMS = {
client_id: 'a81f01ef5d0036415431e8be76c8db0e',
'duration[from]': 200000,
'duration[to]': 205000
};
If you look at $http documentation, on request it applies a default transformation which is $http.defaults.transformRequest and as described will do the following (as you saw) :
If the data property of the request configuration object contains an object, serialize it into JSON format.
What you need to do is override this function by specifying your own transformRequest object.
function appendTransform(defaults, transform) {
// We can't guarantee that the default transformation is an array
defaults = angular.isArray(defaults) ? defaults : [defaults];
// Append the new transformation to the defaults
return defaults.concat(transform);
}
$http({
url: '...',
method: 'GET',
transformResponse: appendTransform($http.defaults.transformResponse, function(value) {
return doTransform(value);
})
});
You need to find a way to get the same syntax as jQuery provide which is :
https://api.soundcloud.com/tracks.json?client_id=a81f01ef5d0036415431e8be76c8db0e&duration[from]=200000&duration[to]=205000
Use a condition is is an object and generate manually your String. Should not be difficult.
that's a strange API - I don't know why they don't do something like "duration_from" rather than requiring duration[from] - as suggested you could certainly transform the request, but if this is just a one off you could also try simply hard-coding it using url escaped values for [ and ]:
var dataToSend = {
client_id: 'a81f01ef5d0036415431e8be76c8db0e',
'duration%5Bfrom%5D': 200000,
'duration%5Bto%5D': 205000
};
$http.get('http://api.soundcloud.com/tracks.json', {params:dataToSend});
The params property is way to transform query in restful way. Just transform data in dataToSend object, and it will work.
This is a URL that should be created:
https://api.soundcloud.com/tracks.json?client_id=a81f01ef5d0036415431e8be76c8db0e&duration%5Bfrom%5D=200000&duration%5Bto%5D=205000

IE8 changing GET request to POST: Angular $http

I am making call to a REST service from my AngularJS app using $http. The issue is whenever I make a GET request from IE8, it gets converted to POST request. Calls with other http methods (POST,PUT) work fine. This happens only with IE8.
Here is my code
```
var request = {method: method, url: url, data: payload};
var promise = $http(request) .then(function (response) {
return response;
});
```
Can someone please help. I have tried sending different types off data payload : null,undefined,empty object, some object. But nothing worked.
I think I have found the solution. We need to send empty string as payload. Or, use $http.get

AngularJS Passing a list into $http.get()

I have a route on my server that is designed to handle a list of objects passed through a GET request. It does this by flattening fields of the same name.
For example:
GET http://example.com/services/echo?list=Hello&list=Stay&list=Goodbye
would be deserialized to a list containing ['Hello', 'Stay', 'Goodbye']
How would I replicate this behavior when using Angular's $http service? One way is to build the URI string manually. Another is to configure the servlet to deserialize the list from one field. But is there a cleaner way to do this, e.g. by using the config object?
This might work
$http({method: 'GET', url: '/someUrl',params:{list:['foo','bar']}).
success(function(data, status, headers, config) {
// this callback will be called asynchronously
// when the response is available
}).

AppState with Google Client API. Update not possible?

We are integrating Google App State into our web based game using Google's API discovery service. Our test code looks like this:
gapi.client.load('appstate','v1',function(response) {
var request = gapi.client.appstate.states.update({ stateKey: 0 });
request.execute(function(result) { console.log(result); });
});
I always get back an HTTP 400 with the message "The update request does not contain any data.". This makes sense since I'm not passing any data, the problem is that I have no idea how to pass the data (aka state) and I can't find any documentation on how to do it. I tried passing some data along with the stateKey
{ stateKey: 0 , data: <some-base64-encoded-data> }
But this still fails with the same message.
After inspecting the library's minified code I'm starting to suspect this feature is still unimplemented.
UPDATE (after doing some more experiments)
I also tried using gapi.client.request like this:
var request = gapi.client.request({
'path': '/appstate/v1/states',
'params': { 'stateKey': '0' },
'method': 'PUT',
'body': {
'kind': 'appstate#updateRequest',
'data': 'ZGF0YQ=='
}
});
But I get a 404 and I think it's because this method passes request parameters in the &stateKey=0 style. On the other hand if I use 'path': '/appstate/v1/states/0' I get a conflict response which is what I was expecting.
Correct me if I'm wrong but I'm starting to believe that the problem is due to inconsistencies between Google's different web APIs which they are now trying to coalesce into a single interface.
In your initial Discovery-based method, you need to pass the data in a parameter named 'resource.'
Here is the Discovery document for appstate/v1: https://www.googleapis.com/discovery/v1/apis/appstate/v1/rpc

should I return the entire record again as a response from server to a POST when I do $update on an angular resource?

In my factory
return $resource('rest/records/:id', {}, {
query: {
method: 'GET',
isArray: true,
// RestSQL has an extra struct around the array
transformResponse: function(data) {
return angular.fromJson(data).records;
}
},
create: { method: 'POST' },
update: { method: 'PUT', params: {id: '#id'},
});
Which is used by a service which is in turn used by a controller.
I get the correct record in the controller.
Then when I edit and want to save the record
I do record.$update();
my rest POST is successful as I get a valid response from server.
But the response from server is just some kind of success message e.g. "{ "number": 2 }".
Now I have an angular template which uses this records properties e.g. {{record.image}}
But as soon as I do record.$update();
records properties disapper and record now simply looks like
record = {"number" : 2}
So should I return the entire record as a response to the POST action or should I update in some other fashion so as to the record doesnt get its properties overwritten by the response from server?
A temporary way of getting around this of course is
$scope.temp = jQuery.extend(true, {}, $scope.record);
$scope.temp.$update();
I am returning the updated object on POST's, PUT's etc. (see also this: Should a RESTful 'PUT' operation return something) all the time. So,
no problem with always returning the updated object in the response
don't use tricks and more code to sove a problem that can be solved by applying a very simple solution (in this case, returning the updated object). I love those fixes: Simple solution, problem solved and code removed instead of adding things here and padding things there etc., making code unreadable und unnecessarily complex.

Categories

Resources