Join the Stack Overflow Community
Stack Overflow is a community of 6.7 million programmers, just like you, helping each other.
Join them; it only takes a minute:
Sign up

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.']);
    }
 ?>
share|improve this question
1  
Read about $http service. The $http does not return the response body, it returns a promise with the response object, that contain the response body among other things like headers, status etc. – Ron Dadon Jan 3 at 8:02
    
Also, for angular to automatically parse your response from PHP to an object and not a string of JSON, you should return a content-type: application/json header with your response, – Ron Dadon Jan 3 at 8:04
1  
@BlissSol expanding on Ron Dadon's answer, since $http is asynchronous and the request variable returns a promise, instead of if (request.success) you'll want to have request.then( function(response) { if (response.data.success) { ... } } ) – Fissio Jan 3 at 8:14
up vote 2 down vote accepted

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;
      }
    });
share|improve this answer
    
I've made all the changes everyone has recommended, but i still get "undefined" for the variable 'request.message'? Additionally, with the changes which you suggested @georgawg then 'request' is still returning the exact same JSON data which i posted originally, (thus, i can't access the values for "success" or "message" contained within the JSON. – BlissSol Jan 4 at 11:00
    
Would my problem be because the values for "success" and "message" are packaged within an array (on the PHP side) before its packaged as JSON and returned? – BlissSol Jan 4 at 11:01
    
See How to debug small programs. – georgeawg Jan 4 at 13:31

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';
              }
          });
        }
    });
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.