How do I POST urlencoded form data with $http without jQuery?
Asked Answered
N

11

199

I am new to AngularJS, and for a start, I thought to develop a new application using only AngularJS.

I am trying to make an AJAX call to the server side, using $http from my Angular App.

For sending the parameters, I tried the following:

$http({
    method: "post",
    url: URL,
    headers: {'Content-Type': 'application/x-www-form-urlencoded'},
    data: $.param({username: $scope.userName, password: $scope.password})
}).success(function(result){
    console.log(result);
});

This is working, but it is using jQuery as well at $.param. For removing the dependency on jQuery, I tried:

data: {username: $scope.userName, password: $scope.password}

but this seemed to fail. Then I tried params:

params: {username: $scope.userName, password: $scope.password}

but this also seemed to fail. Then I tried JSON.stringify:

data: JSON.stringify({username: $scope.userName, password: $scope.password})

I found these possible answers to my quest, but was unsuccessful. Am I doing something wrong? I am sure, AngularJS would provide this functionality, but how?

Normanormal answered 12/7, 2014 at 6:58 Comment(8)
I don't know what is actual problem but did you try this $http({method: 'post', url: URL, data: {username: $scope.userName, password: $scope.password}});Ullyot
Your first method should work, is $scope.userName defined? why didn't you try data: data?Weave
@KevinB: sorry.. I have made the correct edit.Normanormal
@mritunjay: sorry.. I have made the edit.. I was trying the same.Normanormal
@Veer did it work or still you having issues?Kacikacie
@V31: It din't work.. stil facing the issue.. can you help..Normanormal
@VeerShrivastav are you trying to send a form?Kacikacie
@V31: yaa I am sending a form.. not exactly a form.. but some text-fields and passwords..Normanormal
L
414

I think you need to do is to transform your data from object not to JSON string, but to url params.

From Ben Nadel's blog.

By default, the $http service will transform the outgoing request by serializing the data as JSON and then posting it with the content- type, "application/json". When we want to post the value as a FORM post, we need to change the serialization algorithm and post the data with the content-type, "application/x-www-form-urlencoded".

Example from here.

$http({
    method: 'POST',
    url: url,
    headers: {'Content-Type': 'application/x-www-form-urlencoded'},
    transformRequest: function(obj) {
        var str = [];
        for(var p in obj)
        str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
        return str.join("&");
    },
    data: {username: $scope.userName, password: $scope.password}
}).then(function () {});

UPDATE

To use new services added with AngularJS V1.4, see

Legume answered 25/7, 2014 at 21:19 Comment(11)
what if I need to submit multipart/form-data?Monjan
As long as angular embeds jqLite under angular.element, you can simply return angular.element.param(obj);Cabrera
@Cabrera Keep in mind that param() is not implemented in jqLite - code.angularjs.org/1.3.14/docs/api/ng/function/angular.elementBoatel
@AlexPavlov Since which version? I was already using it for quite a while now.Cabrera
@Cabrera I think param() was never available in jqLite. Most likely you have a real jQuery pulled through dependencies of some 3rd party library etc, that's why it works for you. Anyway, the link I posted provides a complete official list of supported functions.Boatel
Yes you're right, as long as jQuery is loaded before Angular, angular.element will point to it. Since angularjs.org itself requires jQuery, people can miss this easily.Cabrera
that make sense use transformRequest to remove JSON stylePomelo
yes, you need to transform the json into form value formatFated
this is another way to go var obj = {a: 1, b: 2}; Object.keys(obj).reduce(function(p, c) { return p.concat([encodeURIComponent(c) + "=" + encodeURIComponent(obj[c])]); }, []).join('&');Instable
While this answer works and seems correct, it was written in 2014 and is now outdated. From Angular 1.4 there is a built in way to do it by using $httpParamSerializer. Check the answers below for an explanation and an example.Unmeriting
@Unmeriting I can't inject $httpParamSerializerJQLike nor $httpParamSerializer, the way it was described here https://mcmap.net/q/74822/-how-do-i-post-urlencoded-form-data-with-http-without-jquery . I am using AngularJS 1.6.6. Every time I inject it into controller I get undefined or $http function :( So I choose this resolution because it just works!Oreilly
T
140

URL-encoding variables using only AngularJS services

With AngularJS 1.4 and up, two services can handle the process of url-encoding data for POST requests, eliminating the need to manipulate the data with transformRequest or using external dependencies like jQuery:

  1. $httpParamSerializerJQLike - a serializer inspired by jQuery's .param() (recommended)

  2. $httpParamSerializer - a serializer used by Angular itself for GET requests

Example with $http()

$http({
  url: 'some/api/endpoint',
  method: 'POST',
  data: $httpParamSerializerJQLike($scope.appForm.data), // Make sure to inject the service you choose to the controller
  headers: {
    'Content-Type': 'application/x-www-form-urlencoded' // Note the appropriate header
  }
}).then(function(response) { /* do something here */ });

See a more verbose Plunker demo


Example with $http.post()

$http.post(
    'some/api/endpoint',
    data: $httpParamSerializerJQLike($scope.appForm.data), // Make sure to inject the service you choose to the controller
    {
       headers: {
         'Content-Type': 'application/x-www-form-urlencoded' // Note the appropriate header
      }
    }
).then(function

How are $httpParamSerializerJQLike and $httpParamSerializer different

In general, it seems $httpParamSerializer uses less "traditional" url-encoding format than $httpParamSerializerJQLike when it comes to complex data structures.

For example (ignoring percent encoding of brackets):

Encoding an array

{sites:['google', 'Facebook']} // Object with array property

sites[]=google&sites[]=facebook // Result with $httpParamSerializerJQLike

sites=google&sites=facebook // Result with $httpParamSerializer

Encoding an object

{address: {city: 'LA', country: 'USA'}} // Object with object property

address[city]=LA&address[country]=USA // Result with $httpParamSerializerJQLike

address={"city": "LA", country: "USA"} // Result with $httpParamSerializer
Toyatoyama answered 21/6, 2015 at 23:11 Comment(10)
How can we use this on $resource inside a factory ?Gelderland
Should be $http.({... instead of` $http.post({...Hypertension
@CarlosGranados Thanks for noticing. Corrected this typo here and in the Plunker demo.Toyatoyama
This worked perfectly after migrating from jQuery to AngularJSUnlace
This is the AngularJS-specific answer I was looking for. I wish the poster would select this as the best answer.Kries
I can't inject $httpParamSerializerJQLike nor $httpParamSerializer, I am using AngularJS 1.6.6. Every time I inject it into controller I get undefined or $http function :(Oreilly
@Oreilly How are you injecting? The Angular 1.6 documentation does not suggest it has changed: docs.angularjs.org/api/ng/service/$httpParamSerializerJQLikeToyatoyama
@Boaz, Its in TypeScript, I inject it similar like this github.com/gitowiec/ciklum-homework/blob/… , but with constructor(protected $httpParamSerializerJQLike, protected $http: angular.IHttpService, protected $q: angular.IQService, protected $timeout: angular.ITimeoutService)Oreilly
Does this work with $http.post(), too? I tried, but it did not work. With $http() and method set to POST, however, everything is fine.Vallejo
@Vallejo $http.post() is a shorthand method with a slightly different signature. Added an example with the arguments signature of $http.post() that should work similiarly.Toyatoyama
T
61

All of these look like overkill (or don't work)... just do this:

$http.post(loginUrl, `username=${ encodeURIComponent(username) }` +
                     `&password=${ encodeURIComponent(password) }` +
                     '&grant_type=password'
).success(function (data) {
Thelen answered 24/3, 2015 at 9:16 Comment(4)
Finally some common senseEmmittemmons
Won't this send the request with the wrong content-type header?Bechance
It worked for me... not sure what the header was, but the request worked and it allowed to successfully authenticate. Why don't you test it out and let us know.Thelen
@Bechance I guess it might depend on the server, I got bad request, until i added { headers: {'Content-Type': 'application/x-www-form-urlencoded'} } as the config arg, or supply use the $http(config) constructor like moices' answer shows. Either way this is superior to the accepted answer since it does not introduce some magic transformation and does not require the user of some auxillary service. Thanks!Woodsman
A
23

The problem is the JSON string format, You can use a simple URL string in data:

$http({
    method: 'POST',
    url: url,
    headers: {'Content-Type': 'application/x-www-form-urlencoded'},
    data: 'username='+$scope.userName+'&password='+$scope.password
}).success(function () {});
Ancestral answered 4/9, 2015 at 16:39 Comment(2)
you have to use encodeURIComponent($scope.userName) to url encode the data or your parameters will get corrupted if user enters value like "&myCustomParam=1"Oligarch
this is the only answer that has worked for me! I skipped success, but $http format is goodWallet
S
4

Here is the way it should be (and please no backend changes ... certainly not ... if your front stack does not support application/x-www-form-urlencoded, then throw it away ... hopefully AngularJS does !

$http({
     method: 'POST',
     url: 'api_endpoint',
     headers: {'Content-Type': 'application/x-www-form-urlencoded'},
     data: 'username='+$scope.username+'&password='+$scope.password
 }).then(function(response) {
    // on success
 }, function(response) {
    // on error
 });

Works like a charm with AngularJS 1.5

People, let give u some advice:

  • use promises .then(success, error) when dealing with $http, forget about .sucess and .error callbacks (as they are being deprecated)

  • From the angularjs site here "You can no longer use the JSON_CALLBACK string as a placeholder for specifying where the callback parameter value should go."

If your data model is more complex that just a username and a password, you can still do that (as suggested above)

$http({
     method: 'POST',
     url: 'api_endpoint',
     headers: {'Content-Type': 'application/x-www-form-urlencoded'},
     data: json_formatted_data,
     transformRequest: function(data, headers) {
          return transform_json_to_urlcoded(data); // iterate over fields and chain key=value separated with &, using encodeURIComponent javascript function
     }
}).then(function(response) {
  // on succes
}, function(response) {
  // on error
});

Document for the encodeURIComponent can be found here

Southwestwards answered 11/6, 2017 at 16:58 Comment(0)
K
3

If it is a form try changing the header to:

headers[ "Content-type" ] = "application/x-www-form-urlencoded; charset=utf-8";

and if it is not a form and a simple json then try this header:

headers[ "Content-type" ] = "application/json";
Kacikacie answered 15/7, 2014 at 7:35 Comment(4)
Not receiving anything. I still received blank $_POST array.!Normanormal
is this $http call in your controller?Kacikacie
one more thing is your server end php?Kacikacie
I have found a solution for the same are you still getting the problem @Veer?Kacikacie
C
2

From the $http docs this should work..

  $http.post(url, data,{headers: {'Content-Type': 'application/x-www-form-urlencoded'}})
    .success(function(response) {
         // your code...
     });
Confutation answered 12/7, 2014 at 7:5 Comment(4)
@Kevin i am not sure about this but..once when i tried sending a string it showed me an errorConfutation
@KevinB Fine..I got it..i think headers are needed to be changed while sending a string..https://mcmap.net/q/75856/-angularjs-http-post-does-not-send-dataConfutation
Note that sending the correct headers would not affect the data which will still need to be urlencoded, one way or another.Toyatoyama
data is still sent in json you must encode the data into x-www-form-urlencoded just adding a header is not enoughDiaphragm
N
2
$http({

    method: "POST",
    url: "/server.php",
    headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
    data: "name='Олег'&age='28'",


}).success(function(data, status) {
    console.log(data);
    console.log(status);
});
Nicolettenicoli answered 18/8, 2017 at 10:13 Comment(1)
Code only answers aren't useful for the community. Please look at How to AnswerUndersexed
D
1

you need to post plain javascript object, nothing else

           var request = $http({
                method: "post",
                url: "process.cfm",
                transformRequest: transformRequestAsFormPost,
                data: { id: 4, name: "Kim" }
            });

            request.success(
                function( data ) {
                    $scope.localData = data;
                }
            );

if you have php as back-end then you will need to do some more modification.. checkout this link for fixing php server side

Dianetics answered 27/7, 2014 at 9:28 Comment(2)
thats exactly NOT what he asked for, he specifically asked how he can get them as x-www-form-urlencoded, because he is running into issues with json stuff posted.Slum
@Slum have you checked the edit history of the question before downvoting..Dianetics
D
1

Though a late answer, I found angular UrlSearchParams worked very well for me, it takes care of the encoding of parameters as well.

let params = new URLSearchParams();
params.set("abc", "def");

let headers = new Headers({ 'Content-Type': 'application/x-www-form-urlencoded'});
let options = new RequestOptions({ headers: headers, withCredentials: true });
this.http
.post(UrlUtil.getOptionSubmitUrl(parentSubcatId), params, options)
.catch();
Dreamworld answered 24/3, 2017 at 13:27 Comment(0)
M
0

This worked for me. I use angular for front-end and laravel php for back-end. In my project, angular web sends json data to laravel back-end.

This is my angular controller.

var angularJsApp= angular.module('angularJsApp',[]);
angularJsApp.controller('MainCtrl', function ($scope ,$http) {

    $scope.userName ="Victoria";
    $scope.password ="password"


       $http({
            method :'POST',
            url:'http://api.mywebsite.com.localhost/httpTest?callback=JSON_CALLBACK',
            data: { username :  $scope.userName , password: $scope.password},
            headers: {'Content-Type': 'application/json'}
        }).success(function (data, status, headers, config) {
            console.log('status',status);
            console.log('data',status);
            console.log('headers',status);
        });

});

This is my php back-end laravel controller.

public function httpTest(){
        if (Input::has('username')) {
            $user =Input::all();
            return  Response::json($user)->setCallback(Input::get('callback'));
        }
    }

This is my laravel routing

Route::post('httpTest','HttpTestController@httpTest');

The result in browser is

status 200
data JSON_CALLBACK({"username":"Victoria","password":"password","callback":"JSON_CALLBACK"}); httpTesting.js:18 headers function (c){a||(a=sc(b));return c?a[K(c)]||null:a}

There is chrome extension called postman. You can use to test your back-end url whether it is working or not. https://chrome.google.com/webstore/detail/postman-rest-client/fdmmgilgnpjigdojojpjoooidkmcomcm?hl=en

hopefully, my answer will help you.

Mathewmathews answered 29/7, 2014 at 5:11 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.