How to do Ajax form validation with inline error messages – without using a plugin

When in comes to validating forms, there are basically two techniques you can use: 1) Server-side validation and 2) Client-side validation. Server-side validation is when form data is submitted, server analyzes then returns the user back to the form when items are invalid. Client-side on the other hand, is when Javascript analyses the fields before actually submitting the data to the server.
Update 4/2/2016: – The code below is not meant to be a “copy and paste” type of thing. You will need some PHP and Javascript debugging experience to successfully integrate into your project.
ajax-inline-errors
Plenty argue (including myself), that server side validation is more secure. This is because client side validation can be manipulated (or simply turned off). But the bad thing about server side validation – is you see the page refresh. This is considered to be bad user experience – especially in mobile.
I’ve seen solutions where they use both server side and client side – with validation rules in Javascript and their server language. But that’s a bit redundant isn’t it? Plus think of the maintenance of code that you have to do. Wouldn’t it be nice to combine both?

Combining both techniques

What we’re trying to achieve is have the security of server side validation, the elegance of displaying the errors inline, as well as have a fall back behavior. So even when users turn off Javascript – you will see the same error messages. Oh and of course, we will also have the good user experience of the page not refreshing when there’s errors.
ajax-errors2
Keep in mind that you will need a bit of programming know how – especially in PHP and Javascript. Ready to get started? Let’s begin.

The Markup

We start with a regular form. The submit action would be a processing page where our server side logic will take place. You can also have the processing page the same as the page where the form is. But I like to keep files separate. Copy the code below into your HTML:

Nothing fancy here. Just a regular form and a couple of fields. Remember to make your field names unique – for this is what we’ll use to validate our form.

The Processing Page

So when our form submits, it passes the $_POST array to this page. If you’re new to validating forms, the code below simply goes through the array and checks it against our rules for each field. Note that in our case – I’m simply checking if first name and email is empty. Of course in the real world, you will have to check for valid email and such.

session_start();
if(isset($_POST)){
  	if (empty($_POST['first_name'])) {
		$_SESSION['errors'][‘first_name'] = ‘First name is missing’;
        	}
	if (empty($_POST[‘email’])) {
		$_SESSION['errors'][‘email'] = ‘email is missing’;
        	}
        if(count($_SESSION['errors']) > 0){
	    //This is for ajax requests:
            if(!empty($_SERVER['HTTP_X_REQUESTED_WITH']) &&  strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') {
                echo json_encode($_SESSION['errors']);
                exit;
             }
	    //This is when Javascript is turned off:
           echo “
    ”; foreach($_SESSION['errors'] as $key => $value){ echo “
  • ” . $value . “
  • ”; } echo “
”;exit; }else{ //form validation successful - process data here!!!! } }

The key to the code above is the check for an Ajax request. Notice the json_encode() method. This is when it’s an Ajax request and we simply echo our error array in JSON format. We will need this to format our inline messages later. The rest of the code is simply handled as if it’s regular server side processing.
Again, notice the part where if it’s NOT an Ajax request – we simply echo out a list of our validation errors. You would probably want to style this better, or even echo it out in the same page as the form. But for the sake of our tutorial, I want to make it short and concise.

Our Javascript

I prefer to write jQuery, so the code below will only work if jQuery is included. The code below is to be added to our form page:

var data = {};
$(document).ready(function() {
  $('input[type="submit"]').on('click', function() {
      resetErrors();
      var url = 'process.php';
      $.each($('form input, form select'), function(i, v) {
          if (v.type !== 'submit') {
              data[v.name] = v.value;
          }
      }); //end each
      $.ajax({
          dataType: 'json',
          type: 'POST',
          url: url,
          data: data,
          success: function(resp) {
              if (resp === true) {
                  	//successful validation
                      $('form').submit();
                  	return false;
              } else {
                  $.each(resp, function(i, v) {
	        console.log(i + " => " + v); // view in console for error messages
                      var msg = '';
                      $('input[name="' + i + '"], select[name="' + i + '"]').addClass('inputTxtError').after(msg);
                  });
                  var keys = Object.keys(resp);
                  $('input[name="'+keys[0]+'"]').focus();
              }
              return false;
          },
          error: function() {
              console.log('there was a problem checking the fields');
          }
      });
      return false;
  });
});
function resetErrors() {
    $('form input, form select').removeClass('inputTxtError');
    $('label.error').remove();
}

Plenty of things going on above. Of course everything is wrapped inside our document.ready() handler, then we put a .click() for our submit button. So every time we click the submit button, we go through each field in the form and create a data object. This object contains the field names and their respective values (you can also use jQuery’s .serialize() for this purpose).
We make an Ajax call to our processing page – where it does the validation in our PHP code previously. Now, remember our server side will echo a JSON object with our field names and error messages? We simply handle this by adding an error class and adding a “label” with the message through jQuery’s .after() function.
ajax-errors4
Of course, if there’s no errors – the form does a hard .submit() – to the same processing page and handled accordingly.

Our CSS

Of course, we have add our styling so our field will look like our screenshots above. Simply add this code inside style tags.

.error {
   color: #ff0000;
   font-size: 12px;
   margin-top: 5px;
   margin-bottom: 0;
}
.inputTxtError {
   border: 1px solid #ff0000;
   color: #0e0e0e;
}

Again, the styles are real basic and you probably want to do better in your own forms.

Conclusion

So there you have it. We’ve combined best of both worlds: server side and client side validation in one solution (thanks to Ajax). Our code has clear separation and very manageable. If a field validation rule has to change – we only need to change it in one place: the server code. Also, our users will benefit from our friendly form – and the way it gracefully tells them when they’ve missed a field and such.
Let me know your thoughts and if you think this solution is a good fit for your projects.

40 Comments

  1. hey, thanks for the tutorial…although something`s wrong on my side…why i’m getting ‘there was a problem checking the fields’ errors in the console? cheers

    Reply
  2. Doesnt work at all for me – even with lastest jquery added to header.
    I have copied and pasted all the code – doesnt even call up the process.php.

    Reply
  3. Works fine for me.
    But when I enter the value for the field the error validation still occurs! For the input fields id and name set is the same. Note I have a multi step form so if successful validation on JS instead of posting the form I would simply hide the 1st step of form and show the 2nd step parts. At last step I would post the whole form.
    Why would the validation still be triggered? I have followed the same process.php. How can I implement this for multi step form, where I can AJAX validate each step of the form? The data from each step should be POSTed together for processing in server, not posted on each step..

    Reply
    • It shouldn’t be that hard. There is just one processing page and a controller. There is no model yet. That comes later when you save / edit data.

      Reply
  4. Not sure if my issues where due to slight changes I made for my scenario but I was experiencing the problem of the errors showing up every time, even when I was 100% sure the validation was correct. I found 2 fundamental problems that resolved this. Firstly, there is no session reset so every time the session was keeping hold of error count > 0. Secondly the ajax code of if (resp === true) seemed a little strange as the resp result is whatever you choose to be your error code. So changing this to if(resp == ”) worked for me.

    Reply
  5. Hello, when I revisited the code, there was the error with $_SESSION. It can be easily replaced with normal array, something like $errors[‘first_name’] = ‘Blah blah’. And then just check if(empty($errors) === false) { json_encode($errors) }. Secondly the problem in jQuery code when receiving response back from PHP script if(resp === true), I just added echo json_encode(true) at the end of the validation if everything was successful.
    Thank you very much for this great tutorial anyway. 🙂

    Reply
  6. Any reason this can’t be optimized so the controller does the actual CRUD if the initial validation succeeds? in this case the javascript would simply navigate the page to the next view (perhaps passed as a parameter in the JSON response).
    The benefit to this would be that only a single call is needed rather than two (the first being for validation and the second the actual CRUD POST (where validation has to be re-done anyway to be safe)

    Reply
  7. Hi! Thanks for this tutorial.
    I have some fields that are arrays (checkboxes) and when submitting the form, it always sends the last array value (last checkbox element) even if not selected. How can I fix that?
    Thanks

    Reply
  8. Thanks a lot for this Michael. This is helpful is keeping the form functional even if JS is turned off.
    If I use these scripts to handle validation in a multi step form (like so https://www.formget.com/multi-page-form-php/)
    should I validate on each step or validate all the step’s fields together in the final step?
    Do you recommend using this AJAX method on multi step forms?
    Thanks!

    Reply
    • Yes I would validate each step because it’s just better user experience. I would keep a flag in session or something that will tell you that each step is valid before continuing, because you might want users to go back a step etc. Yes, AJAX can be good for multi step forms.

      Reply
  9. Very nice, very detailed and extremely helpful. Typically, we don’t have much need to submit and stay on the page. But we have been doing a lot of single-page responsive sites lately with contact forms, so we would rather keep the user right on the page rather than having to reload the entire single page site with an error message. The page is graphically heavy so it makes no sense to load the whole thing again (slider, images, etc would cause a lot of drag). But we also needed to do field validation and all the samples I was finding addressed “success:” but never the handling of detailed field errors, such as “invalid email address”, “first name is required”, etc. So this helped a lot. We have to strip it down a bit because we’re not producing inline errors under each field, but we are updating a single error DIV and setting its style to display=”block”. This was a huge help, so thank you!

    Reply
  10. Hey, I think your site might be having browser compatibility issues.
    When I look at your blog site in Opera, it looks fine but when opening
    in Internet Explorer, it has some overlapping. I just wanted to give you a quick heads up!
    Other then that, superb blog!

    Reply
  11. Guys this is more an idea of how to do something, not really a piece of code you can copy-paste. The quotes are all over the place and you can’t count() arrays, but the basic idea seems to be ok. You just need to write it again, check your server’s log for tips.

    Reply

Leave a Comment.