How do I POST urlencoded form data with $http without jQuery? - javascript

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?

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
URL-encoding variables using only AngularJS services

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:
$httpParamSerializerJQLike - a serializer inspired by jQuery's .param() (recommended)
$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

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) {

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 () {});

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

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";

From the $http docs this should work..
$http.post(url, data,{headers: {'Content-Type': 'application/x-www-form-urlencoded'}})
.success(function(response) {
// your code...
});

$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);
});

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

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();

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.

Related

How to update outlook 2.0 API token using refresh-token?

I have next situation:
Main authentication flow happens on server, then client side obtains these data, since that moment I wanna client be able to update token by itself. It's seems there is all needed data on client(access_token, refresh_token), but I can't figure out how to organize request to https://login.microsoftonline.com/common/oauth2/v2.0/token route.
First I tried to get json response:
$.ajax({
url: `https://login.microsoftonline.com/common/oauth2/token?grant_type=refresh_token&refresh_token=refresh_token&scope=openid%20profile%20offline%20access%20user.read%20mail.read%20contacts.read%20calendars.read&client_id=client&client_secret=secret`,
type: 'POST',
cache: false,
processData: false,
contentType: false,
dataType: 'json',
headers: {
'Host': 'https://login.microsoftonline.com',
'Content-Type': 'application/json'
},
success: function(data) {
...
},
error: function(xhr) {
...
}
});
After that I figured out that it's only possible to get this data with redirect, is it correct? If it is, can someone produce an example of how to implement this, looks like it's needed to create an iframe and handle authorization somehow. Thanks.
UPDATED:
as Alina Li pointed in comment to her answer, there is a solution right in the official doc https://learn.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-auth-code-flow
According to my test, you could using refresh-token through the below code:
var data = "grant_type=refresh_token&refresh_token=refreshToken&client_id=" + appState.clientId;
$http = $http || $injector.get('$http');
$http.post(authUrl + '/token', data, {
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
}).success(function (response) {
}).error(function (err, status) {
});
You don’t need to add scope parameter.
Reference from:
Storing Refresh Token In JavaScript, Getting New Access Token

Angular js $http post not working

I am using http post to get the data from a webservice using the following code..
$http({
method: "post",
url: "SurveyQuestions.asmx/GetSurveyQuestions",
data: JSON.stringify({"empl_id" : '12345' , "Year" : '2015' }),
headers: { 'Content-Type': 'application/json' },
dataType: "json",
contentType: "application/json; charset=utf-8",
}).success(function (response) { //do something})
The above code is working fine using "get" without parameters.
and my webservice for the post is
<WebMethod()> _
<ScriptMethod(ResponseFormat:=ResponseFormat.Json, UseHttpGet:=False)> _
Public Sub GetSurveyQuestions(ByVal Empl_id as string, ByVal Year as string)
Try
//get list of records
Dim js As JavaScriptSerializer = New JavaScriptSerializer
Context.Response.Write(js.Serialize(listSurveyQuestions))
Catch ex As Exception
End Try
End Sub
Web service is executing fine and returning the data to the Method, but the response is empty in the $http and errored out.
you just try to pass the object only adding at the last in url.
This my case i am just adding the employee Id. if you send only employee object only it will also correct.
$scope.removeEmployee = function(employee) {
var method = 'DELETE';
var url = 'http://localhost:8080/AngularJSWithRestful/rest/product/Delete/' + employee.id ;
$http({
method : method,
url : url,
}).then(function successCallback(response) {
$scope.product = response.data.product;
}, function errorCallback(response) {
});
};
Because you are retrieving data and there are no changes being executed on your server (according to your comment) the best thing to do would be to change it to a HttpGet method. Then in angular you should use params property in the passed object to the $http function. This is because HttpGet does not support a message body. From the documentation:
params – {Object.<string|Object>} – Map of strings or objects which will be serialized with the paramSerializer and appended as GET parameters.
Your changed code:
$http({
method: "GET",
url: "SurveyQuestions.asmx/GetSurveyQuestions",
params: {"empl_id" : '12345' , "Year" : '2015' }, // use the params property
headers: { 'Content-Type': 'application/json' },
dataType: "json",
contentType: "application/json; charset=utf-8",
}).then(function (response) { //do something})
Also note that success and error are being marked as obsolete by the angular team. The recommended approach is to use then instead. See the same documentation link.
Deprecation Notice
The $http legacy promise methods success and error have been deprecated. Use the standard then method instead. If $httpProvider.useLegacyPromiseExtensions is set to false then these methods will throw $http/legacy error.
See also AngularJS passing data to $http.get request

HTTP parameter pass for Angular js

Passing parameter for $http with angular js.
$http({
method: 'get',
url: 'http://mmres.baganthandehotel.net/mmresadmin/invoicejson.php',
data: $.param({'chk': '2015-06-02'}),
headers: { 'Content-Type': 'application/json; charset=utf-8'}
})
.success(function(data){
$scope.list = data;
console.log($scope.list);
}),
I can't received the value chk($_GET['chk']) from my server side.Why can't receive these parameter?
With HTTP GET request you can not post data to the server,
Same things applies to angularjs $http get request.
But in angular js $http method we have option to pass query params, example is as below
$http({
url: user.details_path,
method: "GET",
params: {chk: '2015-06-02'}
});
I think you should change your code like this ,
$http({
method: 'get',
url: 'http://mmres.baganthandehotel.net/mmresadmin/invoicejson.php',
params: {chk: '2015-06-02'},
headers: { 'Content-Type': 'application/json; charset=utf-8'}
})
.success(function(data){
$scope.list = data;
console.log($scope.list);
}),
Try:
$http.get('http://mmres.baganthandehotel.net/mmresadmin/invoicejson.php',{
params: {'chk': '2015-06-02'},
headers: { 'Content-Type': 'application/json; charset=utf-8'}
})
.success(function(data){
$scope.list = data;
console.log($scope.list);
}),
Remove the quotation for 'chk' as shown :
data: $.param({chk: '2015-06-02'}),
You will not get params value through $_GET you have to fetch params value by using file_get_contents because from angular you are making request with application/json content type.
$postData = json_decode(file_get_contents('php://input'), true);

How to get Access Token from ASP.Net Web API 2 via AngularJS $http?

I try like this:
$http({ method: 'POST', url: '/token', data: { username: $scope.username, password: $scope.password, grant_type: 'password' } }).success(function (data, status, headers, config) {
$scope.output = data;
}).error(function (data, status, headers, config) {
$scope.output = data;
});
then tried changing the grant_type to a param:
$http({ method: 'POST', url: '/token', data: { username: $scope.username, password: $scope.password }, params: { grant_type: 'password' } }).success(function (data, status, headers, config) {
$scope.output = data;
}).error(function (data, status, headers, config) {
$scope.output = data;
});
Still get the dreaded: {"error":"unsupported_grant_type"}
So I do what no AngularJS developer should ever do, resorted to jQuery:
var data = $('#regForm').serialize() + "&grant_type=password";
$.post('/token', data).always(showResponse);
function showResponse(object) {
$scope.output = JSON.stringify(object, null, 4);
$scope.$apply();
};
Which works like a champ... so my question is: how do we replicate the jQuery $.post() call above using AngularJS $http() so we can grab an access token from the OWIN middleware based /token endpoint in ASP.Net Web API 2?
Do this:
$http({
url: '/token',
method: 'POST',
data: "userName=" + $scope.username + "&password=" + $scope.password +
"&grant_type=password"
})
I think, adding the header {headers: { 'Content-Type': 'application/x-www-form-urlencoded' } to your post request would do the trick. It should be something like this:
$http.post(loginAPIUrl, data,
{headers: { 'Content-Type': 'application/x-www-form-urlencoded' }})
You are getting that error because the default implementation of the OWIN OAuth provider is expecting the post to the "/Token" service to be form encoded and not json encoded. There is a more detailed answer here How do you set katana-project to allow token requests in json format?
But you can still use AngularJs you just have to change the way the $http post is made. You can try the answer here if you don't mind using jquery to change your params How can I post data as form data instead of a request payload? Hope that helps.
You can always watch for the requests being made using the developer console in your browser and see the difference in the request.
But by looking at your jquery code &grant_type=password is being passed in the body not the querystring so the $http call should be
$http({ method: 'POST', url: '/token', data: { username: $scope.username, password: $scope.password ,grant_type:password} }).success(function (data, status, headers, config) {
Similar to achinth, but you can still use the $http.post method (+ data is escaped)
$http.post(loginUrl, "userName=" + encodeURIComponent(email) +
"&password=" + encodeURIComponent(password) +
"&grant_type=password"
).success(function (data) {
//...
1) Note the URL: "localhost:55828/token" (not "localhost:55828/API/token")
2) Note the request data. Its not in json format, its just plain data without double quotes.
"userName=xxx#gmail.com&password=Test123$&grant_type=password"
3) Note the content type. Content-Type: 'application/x-www-form-urlencoded' (not Content-Type: 'application/json')
4) When you use javascript to make post request, you may use following:
$http.post("localhost:55828/token",
"userName=" + encodeURIComponent(email) +
"&password=" + encodeURIComponent(password) +
"&grant_type=password",
{headers: { 'Content-Type': 'application/x-www-form-urlencoded' }}
).success(function (data) {//...
See screenshots below from Postman:
Postman Request
Postman Request Header

$http.error() returns data as string

Here's the code for the entire $http implementation:
$http({
url: jsurl('profile.login'),
method: 'POST',
data: $.param({
username: $scope.username,
password: $scope.password,
csrfmiddlewaretoken: $.cookie('csrftoken')
}),
headers: {'Content-Type': 'application/x-www-form-urlencoded'}
}).
success(function (data) {
$scope.success = true;
}).
error(function (data) {
$scope.success = false;
$scope.errors = data.errors;
});
The issue is that data in $http.error is a string despite returning the following response:
Content-Type:application/json; charset=UTF-8
Body: {"errors":{"username":{"messages":[["Pleaseenteryourusername."]]},"password":{"messages":[["Pleaseenterpassword."]]}},"success":false}
In jQuery I would normally use $.parseJSON() however I keep hearing about how I shouldn't use jQuery code within Angular code (I've yet to understand why this is) so I'm wondering if there's a more Angular canonical method to parsing error response to JSON.
Yes, there is angular.fromJson utility function. See http://docs.angularjs.org/api/angular.fromJson

Categories