Getting PHP AJAX response data with Angular $http Service

2.7k Views Asked by At

I'm sorry if this is repeating previous questions, but i haven't been able to find a solution which seems to work with my problem & im new to Angular.

I have an Angular form, which communicates data with PHP to send an email, and my problem is with handling the JSON response from the PHP (as the PHP communicates back whether it succeeded within the JSON itself, along with a message). I can't seem to get the code to respond based on the "success" value contained within the JSON, nor actually display the "message.

The JSON response data looks like this (when it fails due to an email issue): enter image description here

So my angular code needs to respond based on "success" being true or false, while also displaying the "message" which is passed by AJAX in JSON.

My Angular Controller code:

app.controller('ContactController', function ($scope, $http) {
    $scope.result = 'hidden'
    $scope.resultMessage;
    $scope.formData; //formData is an object holding the name, email, subject, and message
    $scope.submitButtonDisabled = false;
    $scope.submitted = false; 
    $scope.submit = function(contactform) {
        $scope.submitted = true;
        $scope.submitButtonDisabled = true;
        if (contactform.$valid) {
            var request = $http({
                method  : 'POST',
                url     : 'php/contact.php',
                data    : $.param($scope.formData),  //param method from jQuery
                headers : { 'Content-Type': 'application/x-www-form-urlencoded' } 
            });
            if (request.success) { 
                console.log(request);
                $scope.submitButtonDisabled = false;
                $scope.result='bg-success';
                $scope.resultMessage = request.message;
              } else {
                $scope.submitButtonDisabled = true;
                $scope.resultMessage = request.message;
                //$scope.resultMessage = "Opps!... something went wrong.  Please Contact OpenHouse directly to let them know of this error.";
                $scope.result='bg-danger';
            };
               //};
           } else {
            $scope.submitButtonDisabled = false;
            $scope.resultMessage = 'Failed <img src="http://www.chaosm.net/blog/wp-includes/images/smilies/icon_sad.gif" alt=":(" class="wp-smiley">  Please fill out all the fields.';
            $scope.result='bg-danger';
        }
    }
});

My PHP Code:

<?php

  require_once ("class.phpmailer.php");   // Include phpmailer class
  ini_set('display_errors', 'On');
  error_reporting(E_ALL | E_STRICT);

  if (isset($_POST['inputFirstName']) && isset($_POST['inputLastName']) && isset($_POST['inputEmail']) && isset($_POST['inputPhone']) && isset($_POST['inputMessage'])) {

    //check if any of the inputs are empty
    if (empty($_POST['inputFirstName']) || empty($_POST['inputLastName']) || empty($_POST['inputEmail']) || empty($_POST['inputPhone']) || empty($_POST['inputMessage'])) {
        $data = array('success' => false, 'message' => 'Please fill out the form completely.');
        echo json_encode($data);
        exit;
    }

    $message=
    'First Name:    '.$_POST['inputFirstName'].'<br />
    Last Name:  '.$_POST['inputLastName'].'<br />
    Phone:  '.$_POST['inputPhone'].'<br />
    Email:  '.$_POST['inputEmail'].'<br />
    Comments:   '.$_POST['inputMessage'].'
    ';

    $mail = new PHPMailer();        // Instantiate the PHPMailer Class
    $mail->IsSMTP();                // enable SMTP
    $mail->SMTPDebug = 1;           // debugging: 1 = errors and messages, 2 = messages only
    $mail->SMTPAuth = true;         // SMTP authentication enabled
    $mail->SMTPSecure = 'ssl';      // secure transfer enabled + REQUIRED for Gmail (either SSL or TLS)
    $mail->Host = "smtp.gmail.com"; //Gmail SMTP Server to relay thru
    $mail->Port = 465; // Port 465 as we're using SSL... or use Port 587 for TLS
    $mail->IsHTML(true);                               // We're sending a HTML formatted message
    $mail->Username = "[email protected]"; // Gmail account for authentication
    $mail->Password = "*********";                     // Gmail password for authentication
    $mail->SetFrom("[email protected]");   // The email is being sent from this address
    $mail->Subject = "Website Contact Form Enquiry";   // The subject line of the email
    $mail->Body = ($message);                          // The actual email message to be sent
    $mail->AddAddress("[email protected]"); // The email is being sent to this address

   if(!$mail->send()) {
     echo json_encode(['success' => false, 'message' => 'Message could not be sent. Mailer Error: ' . $mail->ErrorInfo]);
     exit;
   }

   error_log("Data: ".$data['success']." Message: ".$data['message']);
   echo json_encode(['success' => true, 'message' => 'Thanks! We have received your message.']);

    } else {
      echo json_encode(['success' => false, 'message' => 'Please fill out the form completely.']);
    }
 ?>
2

There are 2 best solutions below

3
On BEST ANSWER

To start, the $http does not return a request object, it returns a promise that resolves with a response object:

        //var request = $http({
        //It returns a promise
        var promise = $http({
            method  : 'POST',
            url     : 'php/contact.php',
            data    : $.param($scope.formData),  //param method from jQuery
            headers : { 'Content-Type': 'application/x-www-form-urlencoded' } 
        });
        //Use .then method to receive response
        promise.then(function (response) {
          var request = response.data; 
          if (request.success) {
            console.log(request);
            $scope.submitButtonDisabled = false;
            $scope.result='bg-success';
            $scope.resultMessage = request.message;
          }
        });

It is important to realize that the $http service immediately returns a pending promise. The promise is later resolved (either fulfilled or rejected) when the response comes back from the server.

Use the .then method of the promise to provide success and rejection handlers that resolve with either the fulfilled or rejected response.

For more information, see: AngularJS $http Service API Reference - General Usage


UPDATE

The AngularJS framework by default encodes and posts using Content-Type: 'application/json'.

To receive JSON data in a PHP backend, do something like:

$json = file_get_contents('php://input');
$obj = json_decode($json);

Then the POST with AngularJS can be simplified:

    var promise = $http({
        method  : 'POST',
        url     : 'php/contact.php',
        //data    : $.param($scope.formData),  //param method from jQuery
        data: $scope.data;
        //headers : { 'Content-Type': 'application/x-www-form-urlencoded' }
        //Defaults to:
        //headers: {'Content-Type': 'application/json'} 
    });
    //Use .then method to receive response
    promise.then(function (response) {
      var request = response.data; 
      if (request.success) {
        console.log(request);
        $scope.submitButtonDisabled = false;
        $scope.result='bg-success';
        $scope.resultMessage = request.message;
      }
    });
0
On

Thanks everyone for the help; I was able to return a response after the asyn http call & display it on the screen... But no matter what i tried, it always packages the HTTP headers with the data, within the data response.

If the PHP didn't send an email (I removed all commands for sending email), then the data response would be just data. If the PHP did send an email, then the response would be HTTP headers + data within the data response.

So in the end on the Angular side, i converted the data response to a string, split that string based up { which would give me a new string with just the data (and no headers), some extra \separating the values in the string, and obviously and ending }

So thus, by string manipulation, i was able to get the response i wanted.

Here's the working Angular Controller:

app.controller('ContactController', function ($scope, $http) {
    $scope.result = 'hidden'
    $scope.resultMessage;
    $scope.formData; //formData is an object holding the name, email, subject, and message
    $scope.submitButtonDisabled = false;
    $scope.submitted = false;
    $scope.submit = function(contactform) {
        $scope.submitted = true;
        $scope.submitButtonDisabled = true;
            var promise = $http({
                method  : 'POST',
                url     : 'php/contact.php',
                data    : {
                    firstname: $scope.formData.inputFirstName,
                    lastname: $scope.formData.inputLastName,
                    emailid: $scope.formData.inputEmail,
                    phoneno: $scope.formData.inputPhone,
                    message: $scope.formData.inputMessage
                },
                headers : {'Content-Type': 'application/json'}
            })
            promise.then(function (response) {
              var request = JSON.stringify(response.data);  //convert JSON data to string for manipulation
              var startpos = request.indexOf("{");          //locate '{' as its the start of the data we want
              var endpos = request.lastIndexOf("}");        //locate '}' as its the end of the data we want
              var res = request.slice(startpos, endpos);    //Extract the actual data now we know where it is.
              var newresponse = res.split("\\");            //Split the data into new array
              var answer = request.search("true");          //search the string to see if it contains the word "true" meaning an email was sent.

              if (answer >= 0) {
                $scope.submitButtonDisabled = false;
                $scope.result='bg-success';
                $scope.resultMessage = newresponse[5].replace('"', " ");
              } else {
                $scope.submitButtonDisabled = true;
                $scope.resultMessage = newresponse[5].replace('"', " ");
                $scope.result='bg-danger';
              }
          });
        }
    });