1

I want to change some data before sending it to the server via ng-resource. I use the tranformRequest-Function like this:

    update: {
        method: 'PUT',
        transformRequest: function (data) {
             // modify data then
             return data;
        }
    }

I can modify data this way but in the request my data is always serialized. I want keep my data as JSON. Is this possible with transformRequest or have this to be done in controller. I would prefer to do it in the service. Thx for help

d-bro82
  • 490
  • 1
  • 6
  • 21

4 Answers4

7

Omg i feel like an idiot. You simply have to do

update: {
    method: 'PUT',
    transformRequest: function (data) {
         // modify data then
         return angular.toJson(data);
    }
}
d-bro82
  • 490
  • 1
  • 6
  • 21
  • Carefull this won't work in all case, if you check the implementation my defaultToJson (which is from angular-resource) you see that it use some condition before usung that angular.toJson). So it may work for you but it won't work for all this is why i have a more complicated answer. – Walfrat Jan 13 '16 at 08:10
  • Ok, i will consider this. Ty – d-bro82 Jan 13 '16 at 08:52
4

Here's an example I'm using in my app. Callers of the $resource methods pass in a simple list of parameters as JSON, and the transformRequest bundles the parameters into the format expected by the API I'm using.

var myServices = angular.module('myServices', ['ngResource']);
...
myServices.factory('MyServer', ['$resource', function($resource){
    var formatLoginRequest = function(data) {
        // input looks like: {username:"imauser", pw:"password"}
        // output should be: {request: {cmd:"login", username:"imauser", pw:"password"}}
        data.cmd="login";
        data = {request: data};
        data = angular.toJson(data);
        return data;
    };
    ...
    return = $resource('https://api.server.com/', {}, {
        login: {method:'POST', params:{}, isArray:false, transformRequest:formatLoginRequest },
        ...other methods defined here...
});

As noted elsewhere, angular.toJson() won't correctly serialize all data types, but it is sufficient for my case with JSON.

Randy
  • 4,351
  • 2
  • 25
  • 46
Matthew Marichiba
  • 1,942
  • 1
  • 23
  • 24
2

In case somebody else comes across this, Angular provides default transformations for objects. The $http service exposes defaults.transformRequest, which checks if the data property is an object and automatically serializes it to JSON.

For this particular case, i would do a simple check if data is an object and if not make it one and override the $http.defaults.transformRequest.

function appendTransform(defaults, transform) {
  defaults = angular.isArray(defaults) ? defaults : [defaults];
  return defaults.concat(transform);
};

update: {
    method: 'PUT',
    transformRequest: 
 appendTransform($http.defaults.transformResponse,function(data) {
      data = angular.isObject(data) ? data : {data};
      return data;
     })
}
Leo Much
  • 629
  • 5
  • 6
0

Yes it is. A bit troublesome and ulgy but here it is :

// from angular-resource
var toString= function() {
    var value = [];
    _.forEach(this, function(e) {
            value.push('' + e);
            });
        return '[' + value.join(', ') + ']';
      };
      var isObject = function isObject(value) {
          // http://jsperf.com/isobject4
          return value !== null && typeof value === 'object';
        };
    var isFile = function(obj) {
      return toString.call(obj) === '[object File]';
    }


    var isFormData = function(obj) {
      return toString.call(obj) === '[object FormData]';
    }


    var isBlob = function(obj) {
      return toString.call(obj) === '[object Blob]';
    }
    var defaultToJson = function(d) {
          return isObject(d) && !isFile(d) && !isBlob(d) && !isFormData(d) ? angular.toJson(d) : d;
    };
    this.typeServiceProcessData = function(d){
             //[put your code here for to change data this will be called before angular default serialization to the server]
    };
    this.typeServiceProcessJsData = function(d){
        //[for data that come back from the server after getting parse by default angular json parsing]
    };


// sample creation of a resource method, be really carefull about the order in transformResponse and transformRequest

'get': {method:'GET', transformResponse:[$http.defaults.transformResponse[0], this.typeServiceProcessData]},

'create':   {method:'POST', url:baseResourceUrl, transformRequest:[this.typeServiceProcessJsData, defaultToJson]},

It's a big huge, it's a code i done some time ago and i copy/pasted some function definition from angular-resource because they weren't define in that scope and weren't accessible from outside of angular resource. To see why they're needed check the defaultToJson function i defined which is the angular default.

If someone has a better way to just copy paste that bunch of function i take too :)

Walfrat
  • 5,363
  • 1
  • 16
  • 35