I'm studying php and angular. Currently exploring the possibilities to send data to server side using $http service. This is what I came up with and it seem to work, but it doesn't look elegant.
Angular code:
$http({
method: 'POST',
url: 'server.php',
data: "newUser=" + JSON.stringify(user),
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
} // set the headers so angular passing info as form data (not request payload)
})
.success(function (respose) {
var x = JSON.parse(respose);
console.log(JSON.parse(x));
}).error(function (err) {
console.log(err);
console.log("some kind of error");
});
This is my php code to receive the data and return it:
if (isset($_POST["newUser"])) {
$newUser = $_POST["newUser"];
echo json_encode($newUser);
}
Why do I have to specify the name of the json I'm passing? I mean the newUser prefix under the data of the request.
Secondly, why do I have to json.parse twice the response in order to convert it back to a JS Object?
Why to I have to specify the headers in order to pass a simple JSON string?
Q1. Why do I have to specify the name of the json I'm passing? I mean the newUser prefix under the data of the request.
Q3. Why to I have to specify the headers in order to pass a simple JSON string?
In PHP, you have global arrays like $_POST & $_GET to receive the data extracted from the request that are on the form of key=value.
And $_POST is filled when using application/x-www-form-urlencoded or multipart/form-data as the HTTP Content-Type.
So in order to use these global arrays, you have to full-fill these two conditions
Okay the alternative way is to use php://input stream to directly read the raw input, so you can send the json string directly.
file_get_contents(“php://input”);
Related
I've been trying to figure how to properly receive an OData response in Javascript for a couple of days. The problem is the response is formatted as an array instead of JSON, so the function JSON.parse(mydata) does not work with the data I am receiving.
My question is two-fold: What is the proper way to request OData to send a response as JSON and/or how do I format my current response to be JSON?
Here is the code that I am using:
$.ajax({
type: "GET",
url: requestUri,
dataType: "script",
accept: "application/json",
success: function(data, request) {
var jsonData = JSON.parse(data);
},
error: function(msg) {
alert(msg);
}})
Here is an example response of logging the variable data with console.log:
{"#odata.context":"http://localhost:5001/odata/$metadata#Movies","value":[{"Title":"Pulp Fiction","Genre":"Action","RunTime":0,"Sales":0,"Key":2}]}
The problem is the response is formatted as an array instead of JSON
It can't be. You can't send "an array" over HTTP. You have to encode it somehow … e.g. as JSON.
jQuery will, unless you override it with the dataType option, use the Content-Type HTTP response header to determine how the data is encoded. If it is JSON, it will parse the JSON.
The value of data is what you would get if you read the raw responseText and passed it through JSON.parse.
So just don't try to parse it manually. jQuery has done it for you.
Skip the step:
var jsonData = JSON.parse(data);
… and just work with data.
NB: The output of JSON.parse is an object, array or other JavaScript data type. JSON data is what you get from JSON.stringify.
If the response is in OData format, as your example shows, but you want it in JSON format that can be parsed by JSON.parse, add $format=json to the OData query, so long as the OData endpoint supports it. I know Dynamics 365 does not.
You can add it to a variable and access it just like that.
var v={"#odata.context":"http://localhost:5001/odata/$metadata#Movies","value":[{"Title":"Pulp Fiction","Genre":"Action","RunTime":0,"Sales":0,"Key":2}]};
//v.value[0] is a json object
console.log(v.value[0]);
or skip the assignment altogether and access this way:
data.value[0]
data.value[0].Genre
data.value[0].RunTime
etc....
I want to use fetch() to query an API endpoint which powers my search page. It returns a list of search results in JSON format.
I also want to pass to the API the current query submitted by the user. The old implementation used jquery and getJSON. Looking at the docs for getJSON, it says that I can pass in a data variable:
data
Type: PlainObject or String
A plain object or string that is sent to the server with the request.
Looking at the docs for fetch, I'm not sure how to pass in data as part of my request. So my question is, how do I pass in a string that will be sent to the server along with my request?
EDIT: I think I can append the query to the request URL, like "/search/?q=Something" and send that. Does anyone have a better way?
If you look at the Body section of the documentation on fetch, it lists several types of values you can use to specify the data sent in your request.
Example using FormData:
var fd = new FormData();
fd.append('q', 'Something');
fetch('/search', {
method : "POST",
body : fd
})
.then(...)
Note that you can't use the body option on GET or HEAD requests (which it seems you may be doing in your case). In that situation, you can build up the parameters using URLSearchParams:
var params = new URLSearchParams();
params.append('q', 'Something');
fetch('/search/?' + params.toString(), {
method: 'GET'
})
.then(...);
You can pass as below
fetch('/users', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
name: 'Hubot',
login: 'hubot',
})
})
If you look at the parameter of my ASP.NET MVC Controller clientId, it's always null.
the only way i can get it to not be null and actually pass the data through successfully is to create a class... but that gets tedious and I can't create a class for every backend function i make just to get this to work.
Is there a way to pass data successfully without creating a class?
Thank you for any help
Angular Factory
PlaylistsFactory.getUsersForClient = function (clientId) {
return $http({
method: 'POST',
url: '/Show/GetUsersForClient',
data: JSON.stringify(clientId)
});
};
Angular Controller
PlaylistsFactory.getUsersForClient(clientId)
.success(function (userList) {
console.log('success!');
});
ASP.NET MVC Controller
public JsonResult GetUsersForClient(string clientId) //clientId is always null unless i create an object
{
...
}
Try making your JSON parameter match the name of your C# parameter as well as encasing that in the data payload as JSON:
return $http({
method: 'POST',
url: '/Show/GetUsersForClient',
data: {clientId: JSON.stringify(clientId)}
});
};
i would recommend that you follow the rules of a RESTful API.
This means you should use the HTTP verbs like GET (getting data), POST (updating data), PUT (creating data), DELETE (deleting data). See http://www.tutorialsteacher.com/mvc/actionverbs-in-mvc
Then you could also add the parameter you want to pass into the route of your API: /Show/GetUsersForClient/{clientId}. See http://blogs.msdn.com/b/webdev/archive/2013/10/17/attribute-routing-in-asp-net-mvc-5.aspx
In this case you disengage the problem of sending data in the body without having a ViewModel on the MVC-Controller side.
When you want to proceed with your solution, then try creating the Object before sending it:
PlaylistsFactory.getUsersForClient = function (clientId) {
var payload = { clientId: clientId }
return $http({
method: 'POST',
url: '/Show/GetUsersForClient',
data: payload
});
};
MVC / WebAPI also sometime choke when the content-type in the request header is text/plain or application/json. For example: a json-object will not be recognized properly by .Net when sent in text/plain.
I have a angular post that sends to my php file, but in the PHP file, I cannot access anything from the post variable. It returns my SUCCESS string, but nothing after that, so my return on the post is "SUCCESS - - - - - " where the data should be between the dashes.
JSON/JS object:
DESCRIPTION: "123321"
LOCATION: "ab_calgary_eighth_ave_pl"
NAME: "123321"
QUANTITY: 123321
TYPE: "cycle"
Angular POST Code:
$scope.insertNewInventoryItem = function()
{
if(typeof ($scope.newItem.LOCATION) == 'undefined')
alert("LocationCannot Be Empty. Please Select An Option From The Drop Down.");
else if(typeof ($scope.newItem.TYPE) == 'undefined')
alert("Type Cannot Be Empty. Please Select An Option From The Drop Down.");
else
{
$http.post("dataaccess/addnewinventory.php", $scope.newItem).then(onAddNewComplete, onAddNewError);
}
}
PHP Page attempting to find the posted values:
<?php
$con = mysqli_connect("localhost", "dbadminuser", "password", "database_demo_inventory");
// Check connection
if (mysqli_connect_errno())
{
echo "FAIL - Failed to connect to MySQL: " . mysqli_connect_error();
}
else
{
echo "SUCCESS - " . $HTTP_POST_VARS['newItem.NAME'] . " - " . $HTTP_POST_VARS['TYPE'] . " - " . $HTTP_POST_VARS["QUANTITY"] . " - " . $HTTP_POST_VARS . " - " . $_POST[0];
}
mysqli_close($con);
?>
Picture of the Request from GOOGLE developer tools:
Picture of return data from the request (see PHP code for where SUCCESS is coming from):
Why can I not access the post variables? Am I missing something here?
By default, Angular transmits data using the Content-Type: "application/json" and PHP can't parse the JSON data into the $_POST natively. You could follow these two steps to resolve this issue:
Step 1: Change the default value of header Content-Type:
angular.module("myApp",[], function($httpProvider){
$httpProvider.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=utf-8';
})
Step 2: Convert the JSON data into key=value pair serialized data. (I'm using jQuery $.param function to convert the data)
$http({
method:"POST",
url: "post.php",
data: $.param($scope.newItem)
}).success(function(data, status, headers, config){
console.log(data);
}).error(function(data, status, headers, config){
console.log(status);
});
Note: $HTTP_POST_VARS is not a super global variable and it has been completely deprecated in PHP 5. I think you could use $_POST.
while chickenrice's answer is true and solves the issue, I'd prefer to use the JSON data as the payload at least for few reasons.
suits if your objects are complicated, contains nested structures.
It allows you to send any kind of object e.g. [[1,2],[3,4]] -
Array(array,array..) This is just impossible to send in uri-encoded
string.
It's not comfortable if you send simple "name=egor&type=lulzsec"
since it will look "verbose".
You CAN omit CSRF tokens with this!
To get this in PHP make use of file_get_contents("php://input"); to get the request body directly.
You would need to have a small wrapper around this. Moreover you might need to whitelist the content type headers to mitigate the CSRF.
EDIT
if (0 === strpos($_SERVER['CONTENT_TYPE'], 'application/json')) {
$input_json = file_get_contents('php://input');
$input= json_decode( $input_json, TRUE ); //convert JSON into array
}
My backend is Apache22/PHP5.4. I've been banging my head against the wall on this issue for days. Just now, I finally cracked it.
Setting content-type to application/x-www-form-urlencoded didn't get the data into input:// or $_POST. Then I came across this thread: https://groups.google.com/forum/#!topic/angular/MBf8qvBpuVE
Not setting Content-Type will make the underlying XHR browser implementation add a correct header
The keys is to set content-type: false. This is my working code, and I don't even have to get the data from input:// it goes directly to $_POST.
var serialized = $httpParamSerializer($scope.formData);
return $http({
method : 'POST',
url : 'your-url-here',
data : serialized,
headers : { 'Content-Type': false }
}).then(
function(response) {
return response;
},
//Network or server error
function(data, status, headers,config,statusText) {
console.log('AJAX failure: status='+status+', statusText='+statusText);
}
);
I am very new to AngularJS, and so I have no idea why setting the header didn't work for me.
For decoding the PHP, I used the following code, which gave me direct access into the POST data, which in my case was JSON. Apparently JSON is a unsupported data structure, so PHP failed to parse it automatically into the POST array:
$jsonText = file_get_contents('php://input');
$decodedText = html_entity_decode($jsonText);
$myArray = json_decode('[' . $decodedText . ']', true);
Explanation:
Line 1 gets the raw data that was sent over from the request (in this case it was from the Angular Controller posted in the OP.
Line 2 decodes the JSON array grabbed in step one, correctly forming it to parse later. Note that in this case, steps one and two both return the exact same looking object.
Line 3 takes the formatted JSON data and decodes it into a PHP array. Now you can use the following to access parts of the array:
$myvar = $myArray[0]["SOME_VARIABLE"];
Thanks for the answers guys!
I'm using AngularJS to $http.post an object, but I also want to include some kind of data in the URL (or some other way) to specify what this object contains and where to parse it in the PHP file. Any idea how I can send a variable similar to GET into the AngularJS post so in PHP I can route the object to the correct if statement for parsing?
Here is my AngularJS code:
$scope.saveSchool=function(){
var schoolData = angular.copy($scope.schoolsModal);
$http.post('data/data.php?schoolModal=save', schoolData).error(function(){
console.log('Did not post data to data.php');
});
};
And here is my PHP code in data.php file in hopes to receive and route the object to the correct if statement for parsing and eventually saving the data.
if (isset($_GET["schoolModal"])) {
if ($_GET["schoolModal"] == "save") {
$postdata = file_get_contents("php://input");
$request = json_decode($postdata);
echo "Acknowledged";
echo $postdata;
}
}
This doesn't work, as it doesn't throw any errors or return anything (PHP). This does work, but I'm unable to route the object in the php file (i would have to create a separate php file just for this angularjs json object).
$scope.saveSchool=function(){
console.log('saveSchool function initiated');
var schoolData = angular.copy($scope.schoolsModal);
$http.post('data/data.php', schoolData).error(function(){
console.log('Did not post data to data.php');
});
};
PHP Script that would need to be in it's own file, as I want to eventually have multiple post functions and parse the data as it's received:
if($_SERVER['REQUEST_METHOD']=='POST'){
$postdata = file_get_contents("php://input");
$request = json_decode($postdata);
echo $postdata;
}
That PHP code works just fine, but i'm unable to route the data to where it needs to go. I don't want to send ALL posts to that if statement. Any ideas, I'm new to AngularJS and PHP and doing my best to pick this up.
Consider this example from a project I did. It only has 1 param 'status', but obviously you can add all of your params to an object like that
postFavorite: function(id, type, record, resource) {
var xsrf = $.param({status: record.prop});
$http({
method: 'POST',
url: this.api_base + '/favorites/'+type+'/'+id,
data: xsrf,
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
withCredentials: true
}).success(function(data, status, headers, config){
if(data.success){
console.log("Success:", data, status, headers, config);
}
});
},