AngularJS - Any way for $http.post to send request parameters instead of JSON?

214,516

Solution 1

I think the params config parameter won't work here since it adds the string to the url instead of the body but to add to what Infeligo suggested here is an example of the global override of a default transform (using jQuery param as an example to convert the data to param string).

Set up global transformRequest function:

var app = angular.module('myApp');

app.config(function ($httpProvider) {
    $httpProvider.defaults.transformRequest = function(data){
        if (data === undefined) {
            return data;
        }
        return $.param(data);
    }
});

That way all calls to $http.post will automatically transform the body to the same param format used by the jQuery $.post call.

Note you may also want to set the Content-Type header per call or globally like this:

$httpProvider.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8';

Sample non-global transformRequest per call:

    var transform = function(data){
        return $.param(data);
    }

    $http.post("/foo/bar", requestData, {
        headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'},
        transformRequest: transform
    }).success(function(responseData) {
        //do stuff with response
    });

Solution 2

If using Angular >= 1.4, here's the cleanest solution I've found that doesn't rely on anything custom or external:

angular.module('yourModule')
  .config(function ($httpProvider, $httpParamSerializerJQLikeProvider){
    $httpProvider.defaults.transformRequest.unshift($httpParamSerializerJQLikeProvider.$get());
    $httpProvider.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded; charset=utf-8';
});

And then you can do this anywhere in your app:

$http({
  method: 'POST',
  url: '/requesturl',
  data: {
    param1: 'value1',
    param2: 'value2'
  }
});

And it will correctly serialize the data as param1=value1&param2=value2 and send it to /requesturl with the application/x-www-form-urlencoded; charset=utf-8 Content-Type header as it's normally expected with POST requests on endpoints.

Solution 3

From AngularJS documentation:

params – {Object.} – Map of strings or objects which will be turned to ?key1=value1&key2=value2 after the url. If the value is not a string, it will be JSONified.

So, provide string as parameters. If you don't want that, then use transformations. Again, from the documentation:

To override these transformation locally, specify transform functions as transformRequest and/or transformResponse properties of the config object. To globally override the default transforms, override the $httpProvider.defaults.transformRequest and $httpProvider.defaults.transformResponse properties of the $httpProvider.

Refer to documentation for more details.

Solution 4

Use jQuery's $.param function to serialize the JSON data in requestData.

In short, using similar code as yours:

$http.post("/foo/bar",
$.param(requestData),
{
    headers:
    {
        'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
    }
}
).success(
    function(responseData) {
        //do stuff with response
    }
});

For using this, you have to include jQuery in your page along with AngularJS.

Solution 5

Note that as of Angular 1.4, you can serialize the form data without using jQuery.

In the app.js:

module.run(function($http, $httpParamSerializerJQLike) {
  $http.defaults.transformRequest.unshift($httpParamSerializerJQLike);
});

Then in your controller:

$http({
    method: 'POST',
    url: myUrl',
    headers: {'Content-Type': 'application/x-www-form-urlencoded'},
    data: myData
});
Share:
214,516

Related videos on Youtube

dnc253
Author by

dnc253

Updated on July 20, 2022

Comments

  • dnc253
    dnc253 almost 2 years

    I have some old code that is making an AJAX POST request through jQuery's post method and looks something like this:

    $.post("/foo/bar", requestData,
        function(responseData)
        {
            //do stuff with response
        }
    

    requestData is just a javascript object with some basic string properties.

    I'm in the process of moving our stuff over to use Angular, and I want to replace this call with $http.post. I came up with the following:

    $http.post("/foo/bar", requestData).success(
        function(responseData) {
            //do stuff with response
        }
    });
    

    When I did this, I got a 500 error response from the server. Using Firebug, I found that this sent the request body like this:

    {"param1":"value1","param2":"value2","param3":"value3"}
    

    The successful jQuery $.post sends the body like this:

    param1=value1&param2=value2&param3=value3
    

    The endpoint I am hitting is expecting request parameters and not JSON. So, my question is is there anyway to tell $http.post to send up the javascript object as request parameters instead of JSON? Yes, I know I could construct the string myself from the object, but I want to know if Angular provides anything for this out of the box.

  • dnc253
    dnc253 over 11 years
    I saw the params in the documentation, and like Gloopy mentions, I need it in the body, and not on the URL. I was wondering if there was some option or something I was missing to do the parameters instead of JSON, but it sounds like I just need to use the transformRequest property.
  • dnc253
    dnc253 over 11 years
    I was wondering if there was something other than having a transformRequest function, but it sounds like there's not. Thanks for heads up about the jQuery param function.
  • Dfr
    Dfr over 11 years
    Non-global per call method is working well for me, but when trying to set up globally via $httpProvider.defaults, then it not working, any clue about this ?
  • kshep92
    kshep92 over 11 years
    WRT configuring it globally, I too am having issues. When I try to do it using the snippet given here, I get an error Cannot read property "jquery" of undefined. How do I fix this? PS. Per-call transformations work.
  • 0xMatthewGroves
    0xMatthewGroves over 11 years
    @kshep92 What is happening is that the transformRequest function is getting called on a request with no data so 'data' is undefined. I added a guard prior to 'return $.param(data);'. Insert this as the first line to the transformRequest function: 'if (data === undefined) return data;' See the edit I made to the answer.
  • marcoseu
    marcoseu almost 11 years
    I guess you just saved me 3 days of work. Thanks!!! I am still trying to figure out if I can intercept request call somehow so that I can inject a custom header for every call.
  • NicolasMoise
    NicolasMoise over 10 years
    In the local case, transformRequest erases the ones that Angular normally does right. In the non-global transformRequest how would one unshift or pull the function instead of over-writing?
  • Gloopy
    Gloopy about 10 years
    @NicolasMoise you can try something like this: transformRequest: [function(d) { return d; }, $http.defaults.transformRequest[0]] replacing that first function with your own. If you don't change it globally the $http.defaults.transformRequest will be a one item array with their default transformRequest handling. See this for reference.
  • NicolasMoise
    NicolasMoise about 10 years
    @Gloopy I found a another solution transformRequest: [function(){//my own function}].concat($http.defaults.transformRequest) by using concat you can run your own function before (or after) the default transformRequest. This also preserves any functions you may have previously added to $http.defaults.transformRequest. In your example you would just be using the first function in your default transformations.
  • Archimedes Trajano
    Archimedes Trajano over 9 years
    Not sure if it is just me, but I found by doing this $.param method, I am no longer able to use ":placeholder" in the URLs.
  • Brent Washburne
    Brent Washburne almost 9 years
    Angular 1.4.0 can no longer modify request headers using transformRequest: stackoverflow.com/a/30492592/584846
  • theRemix
    theRemix almost 9 years
    as of Angular 1.4 you can use $httpParamSerializer instead of jQuery docs.angularjs.org/api/ng/service/$httpParamSerializer
  • m.e.conroy
    m.e.conroy over 8 years
    I've used this method, but I hate it; and took me a long time to figure out why I had to use this.
  • TimoSolo
    TimoSolo over 8 years
    like I said - it feels hacky. Like most of php ;)
  • mbokil
    mbokil about 8 years
    This answer is great. It addresses the 2 main problems with Post from Angular. The header must be set correctly and you have to serialize the json data. If you don't need IE8 support use 1.4+ or later.
  • Mike Feltman
    Mike Feltman about 8 years
    I just implemented this and it resolves issues I was having with post, but this also changes how patch works and appears to have broken all of my uses of $http.patch().
  • Rohit Luthra
    Rohit Luthra about 8 years
    According to me its simplest and easiest...There may be many other ways
  • peterh
    peterh over 7 years
    I am sorry for the "and sacrifice a black hen"-style answer, what is unfortunately common in the current stage of the typescript/node/angular environment.