How to add ajax to existing PHP form

Hi everyone,

I have a contact form which I’m validating with PHP. How would I add jQuery Ajax to the form so that the page doesn’t reload when the form is submitted and error messages are displayed? Or can I do this without using Ajax at all?

I’ve had a look at the jQuery validation plugin https://github.com/jzaefferer/jquery-validation and I like the way the error messages disappear when the correct values are entered into the form inputs. Is this a good plugin to use?

My main concern is how to combine the PHP validation with the jQuery validation. If I use FILTER_VALIDATE_EMAIL to validate the email address then how do I use this with the jQuery validation?

I’m trying to wrap my head around this whole PHP/JavaScript validation.
Any guidance would be appreciated. Thank you in advance!

This is my simplified form and PHP validation:

<?php

if ($_SERVER['REQUEST_METHOD'] == 'POST') {

$errors = array();

$name = filter_var($_POST['name'], FILTER_SANITIZE_STRING);
if (!$name) {
$errors['name'] = 'Please enter your name.';
}

$email_address = filter_var($_POST['email_address'], FILTER_VALIDATE_EMAIL);
if (!$email_address) {
$errors['email_address'] = 'Please enter a valid email address.';
}

$comment = filter_var($_POST['comment'], FILTER_SANITIZE_STRING);
if (!$comment) {
$errors['comment'] = 'Please enter a comment.';
}

if ($name && $email_address && $comment) {
$body = "Name: {$name}\
\
";
$body = wordwrap($body, 70);
mail('simon@whatever.com', 'Contact Form Submission', $body, "From: {$email_address}");
echo '<p><em>Thanks for the comment dude!.</em></p>';
$errors = array();
}

}
?>
<form id="myform" name="contact"  action="" method="post">
<p>Name:
<span class="warning"><?php if (isset($errors['name'])) echo $errors['name']; ?></span></p>
<input type="text" id="name" name="name"  value=
"<?php if (isset($name)) echo $name; ?>" />
<p>Email address:
<span class="warning"><?php if (isset($errors['email_address'])) echo $errors['email_address'];?></span></p>
<input type="text" name="email_address"  value=
"<?php if (isset($email_address)) echo $email_address; ?>" />
<p>Add a comment:
<span class="warning"><?php if (isset($errors['comment'])) echo $errors['comment']; ?></span></p>
<textarea id="text_area" rows="11" cols="72" name="comment"></textarea>
<input type="submit" name="send" id="send_button" value="Send">
</form>

Hey RedBishop,

You will need to use AJAX to submit the form without a page reload, and the simplest way would be to forget about client-side validation and just have your PHP script return the relevant errors:

$('#myform').submit(function(e) {
    e.preventDefault();
    $.ajax({
        type: "POST",
        url: "form.php",
        data: $(this).serialize(),		
        success: function(data){
            if (data.status === 'error') {
                // Loop over data.errors and display the msgs
            } else {
                // Show a success msg
            }
        }					
    });
});

and modify your PHP to return the errors as a JSON object if the form is submitted via AJAX:


if ($_SERVER['REQUEST_METHOD'] == 'POST')
{

    $errors = array();

    $name = filter_var($_POST['name'], FILTER_SANITIZE_STRING);
    $email_address = filter_var($_POST['email_address'], FILTER_VALIDATE_EMAIL);
    $comment = filter_var($_POST['comment'], FILTER_SANITIZE_STRING);

    if (!$name) $errors['name'] = 'Please enter your name.';
    if (!$email_address) $errors['email_address'] = 'Please enter a valid email address.';
    if (!$comment) $errors['comment'] = 'Please enter a comment.';

    if (empty($errors))
    {
        $body = "Name: {$name}\
\
";
        $body = wordwrap($body, 70);

        $mail_sent = mail('simon@whatever.com', 'Contact Form Submission', $body, "From: {$email_address}");

        if (!$mail_sent) $errors['server'] = 'There was an error sending the email';
    }

    // If AJAX request
    if (!empty($_SERVER['HTTP_X_REQUESTED_WITH'])  && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest')
    {
        if ($errors)
        {
            $output = array(
                'status' => 'error',
                'errors' => $errors
            );
        }
        else
        {
            $output = array(
                'status' => 'success',
            );
        }

        header('Content-type: application/json');
        echo json_encode($output);
        exit();
    }
    elseif ($mail_sent)
    {
        echo '<p><em>Thanks for the comment dude!.</em></p>';
    }
}

If you want to add client-side validation, the rules are defined independently from the server-side stuff. Your PHP validation wouldn’t need to be changed… it’ll just act as a fall-back in case the user has JS disabled, or tries to bypass the client-side validation.

Hey fretburner,

it’s good to hear from you and thank you for replying to my post!

I’ve tried the code but when I press send to submit the form, nothing happens. Do you think that I need to change anything to the form itself? The JavaScript I’ve added as is just above the closing body tag.

Thank you.

Did you include a link to the jQuery library just above fretburner’s JS? It’s assuming you have. E.g.

[COLOR="#FF0000"]<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>[/COLOR]
<script type="text/javascript">
$('#myform').submit(function(e) {
    e.preventDefault();
    $.ajax({
        type: "POST",
        url: "form.php",
        data: $(this).serialize(),		
        success: function(data){
            if (data.status === 'error') {
                // [COLOR="#0000FF"]Loop over data.errors and display the msgs[/COLOR]
            } else {
                // [COLOR="#0000FF"]Show a success msg[/COLOR]
            }
        }					
    });
});
</script>

Something also needs to happen with the blue bits.

Hi RedBishop,

Also, you can check in the console to see if there are any errors.
How do I do that?

Hi ralph.m,

Something also needs to happen with the blue bits.

yes, you are right but how would I go about looping over the errors and displaying the messages?

@Pullo,

thanks for the link!

You could use jQuery’s $.each() function to loop the messages and output them by appending them to your span.warning element, something like this:

if (data.status === 'error') {
    $.each(data.errors, function(index, error){
        $('.warning').append(error + '<br>');
    });
}

@fretburner ;

Is it good practice to do this:

header('Content-type: application/json');

I’ve never set the Content-type header im that way before and have never run into any problems.
When might doing this be advantageous?

It would be more important when building an API, as you’d want to properly identify the type of content you’re returning, but it probably doesn’t make a great deal of difference for your average site just making a few internal AJAX requests.

One thing that I was tempted to do was return the errors with a 400 status code, which would trigger the $.ajax error callback… it would make for a better separation between the success and error handling code.

Ok, thanks :slight_smile:

Yeah, it kind of confused me at first seeing data.errors in the success callback.

You could use jQuery’s $.each() function to loop the messages

Ok, thank you.

I’m now able to submit the form but receive an “undefined variable” error message pertaining to

elseif ($mail_sent)

I thus added

$mail_sent = ''; 

below if ($_SERVER[‘REQUEST_METHOD’] == ‘POST’) for the mean time. I am also noticing that the page is reloading when the form is submitted - so it looks like the ajax is not yet working?

I’m going to try tomorrow again. Hope you guys have a great weekend!

Thanks for your assistance.

Hi there Pullo and fretburner,

could one of you please have a look at my form? The PHP is working but not the JavaScript. When I press “send”, the page reloads.

Here are a few things I’ve changed:

I moved

if ($mail_sent) echo '<p><em>Thanks for the comment dude!.</em></p>';

to the if (empty($errors)) code block, otherwise this sentence would not display with JavaScript off.

I also added $mail_sent = ‘’; to below if ($_SERVER[‘REQUEST_METHOD’] == ‘POST’) because I was getting an undefined variable error. Is this correct?

Is it possible to hide the form once it has been successfully submitted and only display a “thanks for…” comment?

One other thing, how difficult would it be show an icon next to the error message? A cross-shaped icon next to the error message which changes into a tick when the correct value is entered into the form input. An example of the functionality that I’m aiming for can be seen at http://jquery.bassistance.de/validate/demo/custom-methods-demo.html

I’m hoping you could please help me get this form working.

Thank you!

My contact form:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>test form</title>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>	
<style type="text/css">
.warning {
    font-weight: bold;
    color: #f00;
}
</style>
</head>
<body>
<div id="container">
<?php

if ($_SERVER['REQUEST_METHOD'] == 'POST')
{
$mail_sent = '';

    $errors = array();

    $name = filter_var($_POST['name'], FILTER_SANITIZE_STRING);
    $email_address = filter_var($_POST['email_address'], FILTER_VALIDATE_EMAIL);
    $comment = filter_var($_POST['comment'], FILTER_SANITIZE_STRING);

    if (!$name) $errors['name'] = 'Please enter your name.';
    if (!$email_address) $errors['email_address'] = 'Please enter a valid email address.';
    if (!$comment) $errors['comment'] = 'Please enter a comment.';

    if (empty($errors))
    {
        $body = "Name: {$name}\
\
";
        $body = wordwrap($body, 70);

        $mail_sent = mail('simon@whatever.com', 'Contact Form Submission', $body, "From: {$email_address}");

        if (!$mail_sent) $errors['server'] = 'There was an error sending the email';

        if ($mail_sent) echo '<p><em>Thanks for the comment dude!.</em></p>';
    }

    // If AJAX request
    if (!empty($_SERVER['HTTP_X_REQUESTED_WITH'])  && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest')
    {
        if ($errors)
        {
            $output = array(
                'status' => 'error',
                'errors' => $errors
            );
        }
        else
        {
            $output = array(
                'status' => 'success',
            );
        }

        header('Content-type: application/json');
        echo json_encode($output);
        exit();
    }

}
?>
<form id="myform" name="contact"  action="" method="post">
<p>Name:
<span class="warning"><?php if (isset($errors['name'])) echo $errors['name']; ?></span></p>
<input type="text" id="name" name="name"  value=
"<?php if (isset($name)) echo $name; ?>" />
<p>Email address:
<span class="warning"><?php if (isset($errors['email_address'])) echo $errors['email_address'];?></span></p>
<input type="text" name="email_address"  value=
"<?php if (isset($email_address)) echo $email_address; ?>" />
<p>Add a comment:
<span class="warning"><?php if (isset($errors['comment'])) echo $errors['comment']; ?></span></p>
<textarea id="text_area" rows="11" cols="72" name="comment"></textarea>
<input type="submit" name="send" id="send_button" value="Send">
</form>

</div>


<script type="text/javascript">
$('#myform').submit(function(e) {
    e.preventDefault();
    $.ajax({
        type: "POST",
        url: "contact-us.php",
        data: $(this).serialize(),		
        success: function(data){
            if (data.status === 'error') {
                    $.each(data.errors, function(index, error){
        $('.warning').append(error + '<br>');
    });
            } else {
                echo'<p>halleluja</p>';
            }
        }					
    });
});
</script>
</body>
</html>

Hi RedBishop,

The first thing I noticed was an error in the JS. Towards the bottom of the form you have:

echo'<p>halleluja</p>';

which needs to be something like:

$("#result").html('<p>halleluja</p>');

Try changing that and seeing if it makes a difference.

Sure. Just do something like:

$("form").replaceWith( "<h2>Thanks, dude!</h2>" );

in the success callback.
I’m not sure if this is a good idea though.

That’s not difficult. Just add them as background images to the CSS. You already have a class of warning, so you would need to add a class of valid as well.

Hopefully this helps you somewhat.

@fretburner ; was more involved in this thread than I was, so let’s wait and see what he says.
If he’s tied up though and you get stuck, I’ll get a demo up and running on my machine and see what can be done.

I’d missed the fact that the code was all from a single file, rather than two separate scripts… that being the case, here’s the amended PHP/JS. I’ve incorporated Pullo’s suggested change in there, plus the error handling isn’t delt with in the success callback anymore. It works with or without JS enabled:


<?php

$mail_sent = false;
$success_msg = 'Thanks for the comment dude!';

if ($_SERVER['REQUEST_METHOD'] == 'POST')
{
    $errors = array();

    $name = filter_var($_POST['name'], FILTER_SANITIZE_STRING);
    $email_address = filter_var($_POST['email_address'], FILTER_VALIDATE_EMAIL);
    $comment = filter_var($_POST['comment'], FILTER_SANITIZE_STRING);

    if (!$name) $errors['name'] = 'Please enter your name.';
    if (!$email_address) $errors['email_address'] = 'Please enter a valid email address.';
    if (!$comment) $errors['comment'] = 'Please enter a comment.';

    if (empty($errors))
    {
        $body = "Name: {$name}\
\
";
        $body = wordwrap($body, 70);

        $mail_sent = mail('simon@whatever.com', 'Contact Form Submission', $body, "From: {$email_address}");

        if (!$mail_sent) $errors['server'] = 'There was an error sending the email';
    }

    // If AJAX request
    if (!empty($_SERVER['HTTP_X_REQUESTED_WITH'])  && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest')
    { 
        if ($errors) 
        {
            $output = array(
                'status' => 'error',
                'errors' => $errors
            );
            header($_SERVER['SERVER_PROTOCOL'] . ' 400 Bad Request');
            header('Content-type: application/json');
            echo json_encode($output);
        } else {
            echo $success_msg;
        }
        exit();
    }
}  
?>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> 
<html lang="en">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>test form</title>
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>	
    <style type="text/css">    
    .warning {
        font-weight: bold;
        color: #f00;
    }
    </style>
</head>
<body>
    <div id="container">
        <?php if ($mail_sent): ?><p><em><?php echo $success_msg ?></em></p><?php endif ?>
        <form id="myform" name="contact" action="" method="post">
            <p>Name:
            <span class="warning name"><?php if (isset($errors['name'])) echo $errors['name']; ?></span></p>
            <input type="text" id="name" name="name"  value="<?php if (isset($name)) echo $name; ?>" />
            <p>Email address:
            <span class="warning email_address"><?php if (isset($errors['email_address'])) echo $errors['email_address'];?></span></p>
            <input type="text" name="email_address"  value="<?php if (isset($email_address)) echo $email_address; ?>" />
            <p>Add a comment:
            <span class="warning comment"><?php if (isset($errors['comment'])) echo $errors['comment']; ?></span></p>
            <textarea id="text_area" rows="11" cols="72" name="comment"></textarea>
            <input type="submit" name="send" id="send_button" value="Send">
        </form>
    </div>

    <script type="text/javascript">
    $('#myform').submit(function(e) {
        e.preventDefault();
        $('.warning').html('');
        $.ajax({
            type: "POST",
            url: "contact-us.php",
            data: $(this).serialize(),		
            success: function(message) {
                $("#myform").replaceWith('<p><em>'+message+'</em></p>');
            },
            error: function(xhr) {
                var response = $.parseJSON(xhr.responseText);
                $.each(response.errors, function(index, error) {
                    $('.warning.'+index).append(error + '<br>');
                });
            }					
        });
    });
    </script>
</body>
</html>

Hi Pullo and fretburner,

how are the both of you doing?

I hope you’ve survived all of the new year’s parties!

Thank you very much for assisting me with my contact form. I have a few questions if you don’t mind…

To show an “error icon” next to the error message I have added a class to the jQuery:
$(‘.warning.’+index).append(error +‘<br>’).addClass(“invalid”);

This displays the error icon but I’d like to replace it with a “success/valid” icon when the correct value is entered into the form input. At the moment the error icon will continue to show even when the error message disappears after the correct values have been entered and the form has been submitted.

Is it possible for the icon and messages to appear/disappear whilst the values are entered into the inputs and without having to submit the form? A kind of instantaneous form validation? For example, a form displays a number of error messages together with the error icons. The correct value is then entered into the input, the message disappears and the error icon is replaced with a success/valid icon. This happens without form submission.

Please let me know what you think of this.

Thank you for time and help.

Hi RedBishop,

Yeah I had a great Xmas/New Year break thanks, how about yourself?

Are you wanting to use the jQuery validation plugin that you mentioned earlier in this thread? If so, this should be pretty straightforward to do.

Yeah I had a great Xmas/New Year break thanks, how about yourself?

Same here, thank you. And congratulations on winning the PHP Award! It’s well-deserved!

Are you wanting to use the jQuery validation plugin that you mentioned earlier in this thread?

To be honest, I don’t know. Is it possible to add the same kind of functionality to the script that I’m presently using without using the plugin? How difficult would it be to implement it? I don’t want you to spend time helping me with a form and then I end up using another script/plugin. But at this stage I’m still testing and comparing various things.

Your thoughts?

Thanks :slight_smile:

It’s probably easier to use the plugin to do those things (even if it does mean changing the existing code a little). I’ve rewritten the page to show how you’d achieve the result you want:

(function() {
    $("#myform").validate({
        errorElement: "span",
        errorPlacement: function(error, element) {
            error.insertAfter( element );
        },
        success: function(label) {
            label.text("ok!").addClass("success");
        },
        submitHandler: submitForm,
        rules: {
            name: {
                required:true
            },
            email_address: {
                required:true,
                email: true
            },
            comment: {
                required:true 
            }
        }
    });
    
    function submitForm(form) {
        $.ajax({
            type: "POST",
            url: "contact-us.php",
            data: $(form).serialize(),        
            success: function(message) {
                $(form).replaceWith('<p><em>'+message+'</em></p>');
            }                  
        });
    };
})();

The form itself needs a few changes. As the validation plugin adds error elements to the form when it needs them, we need to remove them from the initial form display and only show them if the form is submitted normally (non-ajax):


<form id="myform" name="contact" action="" method="post">
    <p>Name:
    <?php if (isset($errors['name'])): ?>
        <span class="error name"><?php echo $errors['name']; ?></span>
    <?php endif ?>
    </p>
    <input type="text" id="name" name="name"  value="<?php if (isset($name)) echo $name; ?>" />
    <p>Email address:
    <?php if (isset($errors['email_address'])): ?>
        <span class="error email_address"><?php echo $errors['email_address'];?></span>
    <?php endif ?>
    </p>
    <input type="text" name="email_address"  value="<?php if (isset($email_address)) echo $email_address; ?>" />
    <p>Add a comment:
    <?php if (isset($errors['comment'])): ?>
        <span class="error comment"><?php echo $errors['comment']; ?></span>
    <?php endif ?>
    </p>
    <textarea id="text_area" rows="11" cols="72" name="comment"></textarea>
    <input type="submit" name="send" id="send_button" value="Send">
</form>

The PHP code can be simplified, as we no longer need the ajax error stuff:


$mail_sent = false;
$success_msg = 'Thanks for the comment dude!';

if ($_SERVER['REQUEST_METHOD'] == 'POST')
{
    $errors = array();

    $name = filter_var($_POST['name'], FILTER_SANITIZE_STRING);
    $email_address = filter_var($_POST['email_address'], FILTER_VALIDATE_EMAIL);
    $comment = filter_var($_POST['comment'], FILTER_SANITIZE_STRING);

    if (!$name) $errors['name'] = 'Please enter your name.';
    if (!$email_address) $errors['email_address'] = 'Please enter a valid email address.';
    if (!$comment) $errors['comment'] = 'Please enter a comment.';

    if (empty($errors))
    {
        $body = "Name: {$name}\
\
";
        $body = wordwrap($body, 70);

        $mail_sent = mail('simon@whatever.com', 'Contact Form Submission', $body, "From: {$email_address}");

        if (!$mail_sent) $errors['server'] = 'There was an error sending the email';
    }
}  

There’s a gist of the complete page code here: https://gist.github.com/anonymous/8316258

Hey fretburner,

thank you very much for all of your assistance. I really do appreciate it and I’ll test the code in a short while.

Do you have any experience with updating a database? I am trying to update multiple rows using some code that another forum member - droopsnoot - helped me with a few months earlier. I am going to start a new PHP thread where I’ll post the code. Would you mind having a look at it? Perhaps you will know how I can modify the code so that the updates will work.

Thank you so much!