20

I'm new to the scene and I want to use Angular.js to make an HTTP POST request. I'm accessing PHP scripts which have parameters that are just POST variables. What gets returned from each script is a JSON string. Normally in an HTML form you can make such a request like:

<form method="post" action="url.php">
<input name="this">
<input name="that">
<input value="Submit">
</form>

Depending on your input and after you click submit, JSON data1 will return something like this: { "code" : 1 }

I have no access to the scripts or to the servers that hosts them.

I was wondering if it's possible for Angular.js to read the JSON data1, match that data1 to what they're defined in my JSON data2, and then output them to my view (<pre>data2</pre>).

For example, if { "code" : 1 } is retrieved, I want my JSON to output the value for code #1:

{ "code" : [
  { 1: "User already logged in." }, 
  { 2: "Wrong parameters, try again."}, 
  { 3: "etc., etc." }
 ] 
};

Here's my attempt:

<form ng-controller="PhpCtrl" name="f1">
<input type="text" name="name">
<input type="text" name="password">
<pre ng-model="codeStatus">{{codeStatus}}</pre>
<input type="submit" ng-click="add()" value="Submit">
</form>

function PhpCtrl($scope, $http, $templateCache) {
    $scope.method = 'POST';
    $scope.url = 'url.php';
    $scope.codeStatus = "";

    $scope.add = function() {

        $http({
            method: $scope.method, 
            url: $scope.url,
            headers: {'Content-Type': 'application/x-www-form-urlencoded'},  
            cache: $templateCache
        }).
        success(function(response) {
            $scope.codeStatus = response.data;
        }).
        error(function(response) {
            $scope.codeStatus = response || "Request failed";
        });
        return false;   
    };
}

All it's posting so far to the view is "Request failed" lol, although it's processing HTTP/1.1 200. I know I still have a ways to go but I would appreciate any help. Once I figure out how to post the proper JSON data1 to the view, the next step is matching and outputting the appropriate data2. Thank you in advance!

matenji
  • 365
  • 3
  • 5
  • 12
  • Maybe the request fails because you'r doing a post request without sending data with it, try to put all the form fields in a FormData object and send it with the request by adding this `data: FormData` as argument to the $http request after putting all the form field in it or the headers is not correct. Hope this help. – Yahya KACEM Mar 29 '13 at 17:16
  • Thanks for your response. I'm not sure if I'm doing this right, but do I just wrap the form data in FormData as a 'JSON object'? I tried this http://pastebin.com/QMZSr4AZ and it was still processing the 'Request failed' error, so I'm guessing I still failed to send data. – matenji Mar 29 '13 at 19:39
  • 2 things: 1) You shouldn't be setting these values on $scope, $scope is meant for model-binding and all values on it are Watched and their values applied to fields of the same name, which has a performance impact. Just set them as local variables like var method = 'POST', they'll be used in the http function as part of a Closure. 2) Do you know how to get into the JS debugger in Chrome/Firefox? Use that to inspect the Response. In Chrome top-right>Developer Tools, you want Network tab, and Console if you add a debugger; line to the error function. – Chris Moschini Mar 29 '13 at 19:51
  • Hi Chris, thanks for the comment and advice! It makes sense regarding model-binding on $scope so I'll remember to use local variables instead. And I've played around with the JS debugger, but since I'm testing locally it kept throwing an error about same origin policy, so I am using Firefox for the time being. – matenji Apr 01 '13 at 08:08

3 Answers3

48

Acctually the problem is in the backend with PHP you don't retrieve the posted data like usual, this worked for me:

function PhpCtrl($scope, $http, $templateCache) {
  var method = 'POST';
  var url = 'url.php';
  $scope.codeStatus = "";
  $scope.add = function() {
    var FormData = {
      'name' : document.f1.name.value,
      'password' : document.f1.password.value
    };
    $http({
      method: method,
      url: url,
      data: FormData,
      headers: {'Content-Type': 'application/x-www-form-urlencoded'},
      cache: $templateCache
    }).
    success(function(response) {
        $scope.codeStatus = response.data;
    }).
    error(function(response) {
        $scope.codeStatus = response || "Request failed";
    });
    return false;
  };
}

in the PHP file:

$data = json_decode(file_get_contents("php://input"));
echo $data->name;

Hope this help.

Yahya KACEM
  • 2,481
  • 7
  • 34
  • 61
  • Yahya, the developer tried implementing that script but it says it can't get the property "name" from a non-object. Is the line (echo $data->name;) necessary? – matenji Apr 01 '13 at 08:06
  • 1
    No, that's just an example, the line before that is the one needed after that you need to do your data processing and then echo the return message that you want. – Yahya KACEM Apr 01 '13 at 14:46
  • My php version is PHP 5.5.3 and this work fine for me #ta7yaISI #Ta7yaTounes – Mils Jan 20 '14 at 19:10
  • `parse_str(file_get_contents('php://input'), $data);` worked for me using PHP 5.3.13. – Ryan Jul 29 '14 at 04:35
  • This was a huge help! Thanks a lot @YahyaKACEM. Cheers! – henser Jun 26 '15 at 22:21
21

Rather old post... but I figure my solution might come in handy for others as well.

I did not like the

json_decode(file_get_contents("php://input"));

solution... Basically because it seems against good practice (I might be wrong on this)

This is how I got it solved (adapted to the example above)

function PhpCtrl($scope, $http, $templateCache) {
  var method = 'POST';
  var url = 'url.php';
  $scope.codeStatus = "";
  $scope.add = function() {
    var FormData = {
      'name' : document.f1.name.value,
      'password' : document.f1.password.value
    };
    $http({
      method: method,
      url: url,
      data: $.param({'data' : FormData}),
      headers: {'Content-Type': 'application/x-www-form-urlencoded'},
      cache: $templateCache
    }).
    success(function(response) {
        $scope.codeStatus = response.data;
    }).
    error(function(response) {
        $scope.codeStatus = response || "Request failed";
    });
    return false;
  };
}

once this done

data: $.param({'data' : FormData}),
headers: {'Content-Type': 'application/x-www-form-urlencoded'},

you can access the data you normally would in PHP

$data = $_POST['data'];
dGo
  • 2,951
  • 1
  • 18
  • 11
  • Is the `$templateCache` really necessary in the request data? – Jago Aug 24 '14 at 16:51
  • I dont know if anything changed when this was answered, but $.param() is undefined for me, what I got working was to use: $httpParamSerializerJQLike(FormData) – Miguel Suarez Jul 08 '16 at 23:16
  • Alright, seems like you need jQuery for this to work. Otherwise $.param is undefined. – DijkeMark Jul 22 '16 at 11:04
  • yeah... sorry... Should have mentionned that this uses the $.params() function of jQuery – dGo Jul 23 '16 at 21:08
  • Here is the param function as a standalone: `var param = function(data) { var returnString = ''; for (var d in data) { if (data.hasOwnProperty(d)) { returnString += d + '=' + data[d] + '&'; } } return returnString.slice( 0, returnString.length - 1 ); };` – David Rhoderick Aug 29 '16 at 16:47
  • Good solution but PUT, DELETE and OPTIONS neeed something like @Yahya KACEM said from PHP side – boctulus Dec 14 '18 at 21:00
4

A possible alternative it is to use an XHR request handler to serialize the payload of the POST request.

$httpProvider.interceptors.push(['$q', function($q) {
    return {
        request: function(config) {
            if (config.data && typeof config.data === 'object') {
                // Check https://gist.github.com/brunoscopelliti/7492579 for a possible way to implement the serialize function.
                config.data = serialize(config.data);
            }
            return config || $q.when(config);
        }
    };
}]);

Moreover, if you didn't do it before, you've also to change the default content-type header of the post request:

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

Recently I wrote a post on my blog, where you could find more info about this approach, and XHR request interceptor.

Bruno
  • 5,961
  • 6
  • 33
  • 52