0

I am using

error:function(exception){alert('Exception:'+ JSON.stringify(exception));}

to display an exception if there is an AJAX error, and here is the response i get:

Exception:{"readyState":4,"responseText":"","status":200,"statusText":"OK"}

This looks like a successful response to me, but it is the function that is called on error which means something is going wrong.

Here is the page: http://cuttingedgeconversions.com/free-month.html

I have a successful API call to subscribe a new email address to mail chimp using form action. But I do not want to redirect to another page after form submission, so I took out the 'form action' property and I tried adding this API call to script.js which uses ajax.

Here is the HTML:

<form class="email_form_freemonth" method="post">
<h3>Get your first month free</h3>
<div class="form-group customised-formgroup"> <span class="icon-user"></span>
<input type="text" name="full_name" class="form-control" placeholder="Name">
</div>
<div class="form-group customised-formgroup"> <span class="icon-envelope"></span>
<input type="email" name="email" class="form-control" placeholder="Email">
</div>
<!--<div class="form-group customised-formgroup"> <span class="icon-telephone"></span>
<input type="text" name="phone" class="form-control" placeholder="Phone (optional)">
</div>-->
<div class="form-group customised-formgroup"> <span class="icon-laptop"></span>
<input type="text" name="website" class="form-control" placeholder="Website (optional)">
</div>
<!--<div class="form-group customised-formgroup"> <span class="icon-bubble"></span>
<textarea name="message" class="form-control" placeholder="Message"></textarea>
</div>-->
<div>
<br>
<button style="margin: 0 auto" name="submit" type="submit" class="btn btn-fill full-width">GET FREE MONTH<span class="icon-chevron-right"></span></button>
</div>
</form>

Here is freemonth_action.php (which gets called in script.js, seen below):

<?php

session_start();
if($_SERVER['REQUEST_METHOD'] == "POST"){
    $name = trim($_POST['full_name']);
    $email = trim($_POST['email']);
    if(!empty($email) && !filter_var($email, FILTER_VALIDATE_EMAIL) === false){
        // MailChimp API credentials
        $apiKey = '*****';
        $listID = '0cf013d1d9';

        // MailChimp API URL
        $memberID = md5(strtolower($email));
        $dataCenter = substr($apiKey,strpos($apiKey,'-')+1);
        $url = 'https://' . $dataCenter . '.api.mailchimp.com/3.0/lists/' . $listID . '/members/' . $memberID;

        // member information
        $json = json_encode([
            'email_address' => $email,
            'status'        => 'subscribed',
            'merge_fields'  => [
                'NAME'     => $name,
            ]
        ]);

        // send a HTTP POST request with curl
        $ch = curl_init($url);
        curl_setopt($ch, CURLOPT_USERPWD, 'user:' . $apiKey);
        curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_TIMEOUT, 10);
        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT');
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $json);
        $result = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);
        //echo json_decode($result);

        // store the status message based on response code
        if ($httpCode == 200) {
            $_SESSION['msg'] = '<p style="color: #34A853">You have successfully subscribed to CodexWorld.</p>';
        } else {
            switch ($httpCode) {
                case 214:
                    $msg = 'You are already subscribed.';
                    break;
                default:
                    $msg = 'Some problem occurred, please try again.';
                    break;
            }
            $_SESSION['msg'] = '<p style="color: #EA4335">'.$msg.'</p>';
        }
    }else{
        $_SESSION['msg'] = '<p style="color: #EA4335">Please enter valid email address.</p>';
    }
}

I know these are correct because when I used 'form action = scripts/freemonth_action.php' it works. But I don't want the page to redirect on submission, so I have added an ajax call in my script that gets triggered from script.js. I have 2 ajax calls right now in script.js, the first one is working but the second one is not. The weird part is that BOTH RETURN STATUS CODE 200.

script.js with non-nested Ajax calls - WORKING PROPERLY NOW:

$('.email_form_freemonth').on('submit', function (e) {
        e.preventDefault();
        var _self = $(this);
        var __selector = _self.closest('input,textarea');
        _self.closest('div').find('input,textarea').removeAttr('style');
        _self.find('.msg').remove();
        _self.closest('div').find('button[type="submit"]').attr('disabled', 'disabled');
        var data = $(this).serialize();
        $.ajax({
            url: 'scripts/email_freeMonth.php',
            type: "post",
            dataType: 'json',
            data: data,
            success: function (data) {
                _self.closest('div').find('button[type="submit"]').removeAttr('disabled');
                if (data.code == false) {
                    _self.closest('div').find('[name="' + data.field + '"]').css('border-bottom', 'solid 2px red');
                    _self.find('.customised-formgroup').last().after('<div class="msg"><p style="color:red;padding:0;font-size:13px;font-weight:bold;position:absolute">*' + data.err + '</p></div>');
                } else {
                    $('.msg').html('<p style="color:green;padding:0;font-size:13px;font-weight:bold;position:absolute">' + data.success + '</p>');
                    _self.find('.customised-formgroup').last().after('<div class="msg"><p style="color:green;padding:0;font-size:13px;font-weight:bold;position:absolute">' + data.success + '</p></div>');
                    _self.closest('div').find('input,textarea').val('');
                }
            }
        });
        $.ajax({
            url: 'scripts/freemonth_action.php',
            type: "post",
            dataType: 'json',
            data: data,
            success: function (data) {
                _self.closest('div').find('button[type="submit"]').removeAttr('disabled');
                if (data.code == false) {
                    console.log("DATA.CODE == FALSE");
                } else {
                    console.log("DATA.CODE == TRUE");
                }
            }, 
            error:function(exception){alert('Exception:'+ JSON.stringify(exception));}
        });

    });
Tom
  • 461
  • 1
  • 8
  • 24

2 Answers2

1

When you're passing serialized data through the AJAX request, if(isset($_POST['submit'])) won't evaluate as true because the button isn't part of the data being sent through the request. You can use if($_SERVER['REQUEST_METHOD'] == "POST") instead to check if the request was submitted. Just update that in your PHP file and it should work!

Joel H.
  • 690
  • 1
  • 7
  • 16
  • I updated that line but am still getting the exception alerted to the screen, caused by this line: `error: function (exception) { alert('Exception:' + JSON.stringify(exception)); }`, but am still getting all status responses as 200 which is strange. I'm not sure how to debug the php because i can't echo errors to the document because the document is never actually displayed to the user. – Tom Sep 05 '17 at 16:16
  • @Tom does it work with the updated PHP file if you take out `dataType: 'json'` in the AJAX request? I was getting the error response when I was trying to figure it out yesterday but it didn't trigger an error when `dataType` wasn't set. – Joel H. Sep 05 '17 at 16:29
  • I took out that line and now the success function is called instead of the error function which is an improvement! But I alert the data variable passed for both ajax calls, and the second one (which makes the call to the mailchimp api) is empty. I don't know if that's a problem though because all the required data for the api call should be in the php file, which takes the data from the html file – Tom Sep 05 '17 at 16:40
  • i have updated script.js to show the current ajax calls i'm using. I have also incorporated a suggestion by headmax, which was nesting one AJAX call within the other inside the 'sucess' response – Tom Sep 05 '17 at 16:57
  • 1
    @Tom If you separate the requests as they were in the original question, simply updating the PHP file should work. You can leave `dataType: 'json'` in script.js then. – Joel H. Sep 05 '17 at 17:00
  • YOU DID IT! Everything works perfectly now. SO TO SUM UP: -My current script.js being used is under the 'non-nested Ajax calls' -My php has been edited as you said, changing the top line to `if($_SERVER['REQUEST_METHOD'] == "POST")` Thanks so much – Tom Sep 05 '17 at 17:11
0

I think you need to add under you first call ajax {} the second call {into}.

$('.email_form_freemonth').on('submit', function (e) {
        e.preventDefault();
        var _self = $(this);
        var __selector = _self.closest('input,textarea');
        _self.closest('div').find('input,textarea').removeAttr('style');
        _self.find('.msg').remove();
        _self.closest('div').find('button[type="submit"]').attr('disabled', 'disabled');
        var data = $(this).serialize();
        $.ajax({ //WORKS
            url: 'scripts/email_freeMonth.php',
            type: "post",
            dataType: 'json',
            data: data,
            success: function (data) {
                _self.closest('div').find('button[type="submit"]').removeAttr('disabled');
                if (data.code == false) {
                    _self.closest('div').find('[name="' + data.field + '"]').css('border-bottom', 'solid 2px red');
                    _self.find('.customised-formgroup').last().after('<div class="msg"><p style="color:red;padding:0;font-size:13px;font-weight:bold;position:absolute">*' + data.err + '</p></div>');
                } else {
                    $('.msg').html('<p style="color:green;padding:0;font-size:13px;font-weight:bold;position:absolute">' + data.success + '</p>');
                    _self.find('.customised-formgroup').last().after('<div class="msg"><p style="color:green;padding:0;font-size:13px;font-weight:bold;position:absolute">' + data.success + '</p></div>');
                    _self.closest('div').find('input,textarea').val('');
                }
            }
            
            //because you are under an event submit "form" and you ajax post was after this one
            $.ajax({ 
            url: 'scripts/freemonth_action.php',
            type: "post",
            dataType: 'json',
            success: function (data) {
                alert(data);
            }
            });
        });
  • I don't think you can run one ajax call within another because when i tried your code i got a syntax error in my IDE – Tom Sep 04 '17 at 21:12
  • Just read this post https://stackoverflow.com/questions/10089447/jquery-ajax-request-inside-ajax-request –  Sep 04 '17 at 21:22
  • I just tell you need to add the call under the first call because its an action trigger by the submit and the second can be called at the end of the first that the deal we are in asynchronous world but we need event to call that (submit, click, onload ...), the second function ajax need a anonymous function success –  Sep 04 '17 at 21:30
  • I tried putting one ajax call within the other as suggested in the link you gave but i'm still getting the same error. All response statuses are 200 but the response body for freemonth_action.php is empty, and should contain something i think – Tom Sep 04 '17 at 21:51
  • Yes and you need into you page find after the first call ajax the class name .msg, cos on the success ajax you append some html into the page $('.msg').html('

    ' + data.success + '

    '); _self.find('.customised-formgroup').last().after('

    ' + data.success + '

    '); if this html tag dont contain this .msg class the script stop tell me your error may be can i show some online? regards.
    –  Sep 04 '17 at 22:06
  • I'm not able to get an error, except for that i have this default error function: `error: function (exception) { alert('Exception:' + JSON.stringify(exception)); }` which alerts the exception. The fact that when I submit the form I actually see the alert tells me that something is wrong, but i'm not sure how to get a more specific error message. Here is the link to the page: http://cuttingedgeconversions.com/free-month.html – Tom Sep 04 '17 at 22:26
  • I just got your test email lol, but you weren't subscribed to the mailchimp list – Tom Sep 04 '17 at 22:49
  • Just tested i get 2 call ajax and the success for both on the second test i just add a new div on the page with attribute class="msg" and after the registration the message append into this div. –  Sep 04 '17 at 22:50
  • yes sorry cos noscript at home :) lol i will retest with this cross site domain. –  Sep 04 '17 at 22:50
  • success: function (data) { alert(data); } replace alert(data) by the workflow you need for the second ajax. –  Sep 04 '17 at 22:58
  • I am alerting 'data' in both success functions now (the first and second ajax calls), and only see the first one as expected. For some reason the second ajax call is failing, and I still can't find out why because the 'exception' parameter passed when the 'error' function is called (rather than the success function) is not very helpful and can be seen alerted to the screen when you submit the form in the link – Tom Sep 04 '17 at 23:02
  • About alert yes sometime the second alert don't be called, but in the example you call 2 same php file with ajax why you need this? –  Sep 04 '17 at 23:12
  • I don't call the same php file twice, one is freemonth_action.php and the other is email_freemonth.php – Tom Sep 04 '17 at 23:24
  • and the second PHP file do the job, or you still got an error? –  Sep 04 '17 at 23:31
  • both php files are correct, because when I use form action = "freemonth_action.php" everything works. But when I try to do it using ajax in script.js (to avoid the page redirect) the mailchimp api call in freemonth_action.php doesn't work – Tom Sep 04 '17 at 23:34
  • So now you have just this "Exception:{"readyState":4,"responseText":"","status":200,"statusText":"OK"}" and this mean all is ok if you dont want to show it and if all job is good just comment the alert here : error:function(exception){//alert('Exception:'+ JSON.stringify(exception));} –  Sep 04 '17 at 23:34
  • that function that puts the alert to the screen only runs if there is an error though. I think it has something to do with the responseText being empty, because it's not supposed to be empty – Tom Sep 04 '17 at 23:36
  • mailchimp api need some POST fields? did you add it on the second call ajax? –  Sep 04 '17 at 23:37
  • about the exception in the world of ajax this mean the call is a sucess look here more explication https://stackoverflow.com/questions/14713489/error-callback-with-readystate4-status200-statustextsuccess –  Sep 04 '17 at 23:40
  • ok i show the error you call a php page but you return nothing from her, that mean call php via ajax and generate an ouput json for example when you post you can do you workflow adding mail into the database but at the end of the workflow you need to add a echo json_encode("what you want to showed on the page caller"); –  Sep 04 '17 at 23:47
  • After this success(data){} here data is the output of the php echo json_encode($datas); –  Sep 04 '17 at 23:56
  • When you call this page freemonth_action.php after the end of the workflow of this page add an $success['sucess'] = "email test ok"; echo json_encode($success); –  Sep 05 '17 at 00:12