HiveBrain v1.2.0
Get Started
← Back to all entries
patternphpMinor

Ajax form validation

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
formajaxvalidation

Problem

This is my first ever attempt at Ajax form validation, and everything works as expected, the final true example will hold a lot more input fields than in my testing scripts which are below.

The file is expected to get a lot bigger as in my testing I have only used 3 input fields, how can I improve on this:

HTML file


Login Details
Your Email:
Password:

Account Details
Your Username:


As you can see in the event of an onblur on the input fields I call the function ajax. I also send with the function a parameter which is exact to the id. Here is my function:

JavaScript

function ajax (id) {

var value = $('#' + id).val();
$('#' + id).after('');

if (id === 'email') {

    $.post('http://www.example.com/ajax.php', {email: value},

    function (response) {
        $('#email_error, #email_success').hide();
        setTimeout(function(){
            $('.loading').hide();
                finish_ajax (id, response);
        }, 1000);
    });
}

if (id === 'password') {

    $.post('http://www.example.com/ajax.php', {password: value},

    function (response) {
        $('#password_error, #password_success').hide();
        setTimeout(function(){
            $('.loading').hide();
                finish_ajax (id, response);
        }, 1000);
    });
}

if (id === 'username') {

    $.post('http://www.example.com/ajax.php', {username: value},

    function (response) {
        $('#username_error, #username_success').hide();
        setTimeout(function(){
            $('.loading').hide();
                finish_ajax (id, response);
        }, 1000);
    });
} 

return false;
}

function finish_ajax (id, response) {

$('#' + id).after(response).fadeIn(2000);
}


Here is what I have tried to do:

-
With the id that I send with the function I assign the value of the input field to a variable named value.

-
Using the same id I then assign a loading div which contains a gif image in my css.

-
Depending on the id send the correct request with the correct na

Solution

Here's a few things I can observe at first glance:

HTML

-
form elements don't accept input fields as direct child’s, so you should place your submit button inside a wrapper element.

-
I don't know about your visual aspect, but you should use CSS to format your elements and keep HTML to a minimum.

-
Your password field should have the type password as to allow the browser to obfuscate the characters being typed.

-
If you're using jQuery, you're better of going with the .blur() event instead of giving onblur attribute to all elements subjected to validation.

Your HTML form would become something like:


  
    Login Details
    Your Email:
    
    Password:
    
  
  
  Account Details
    Your Username:
    
  
  
    
  


JQUERY

Your jQuery currently uses the same code over and over, the best option is always to make scripts as generic as possible, to minimize the amount of code that as to be downloaded and interpreted by the browser. Also, in future maintenance, you'll find it easy to deal with a small generic code then a large element specific one.

-
As mentioned above, with the jQuery .blur() function, you can bind the event to all inputs inside the target form and start creating a more generic validation solution.

-
Instead of having an if statement to ascertain the element subject to validation, send to the PHP file the field collected and its value.

-
No need for specific error elements for each input subjected to validation, use classes and target then thru the input id attribute, that in conjunction with a generic class for messages gives your the target element for the user messages.

-
If you are appending the element .loading to the form, you should also remove it when not needed. If the user keeps triggering the blur in the same input field, the element .loading keeps being added and you end up with tons of them.

Your jQuery code to validate the above form would become something like:

$('#myForm input').blur(function() {

  var id = $(this).attr("id");
  $('#' + id).after('');

  $.post('http://www.example.com/ajax.php', {field:id, value:value}, function (response) {
    $('.'+id+'.msg').hide();
    setTimeout(function() {
      $('.loading').remove();
      finish_ajax (id, response);
    }, 1000);
  });

});

function finish_ajax (id, response) {
  $('#' + id).after(response).fadeIn(2000);
}


PHP

Your PHP code falls under the same issues as the jQuery code, that is, repeating several chunks of code that latter on will prove difficult to maintain.

-
If you're using a POST method, check for it and the specific variables necessary to execute the script, otherwise, bailout.

-
Perform some cleanup to the values before using them.

-
Since you're querying the same table, having the field passed along with the value, proves useful to have a single database line to maintain instead of several across the script.

You can choose to mascaraed the field name if your really want to obfuscate what's being done.

-
When using many If elseif else statements, the best option is to migrate to a switch case statement. Easy to maintain, read and "upgrade".

-
If the HTML that this script is outputting is the same, changing only the text and a class, best is to make use of variables to store the desirable values and have one single like with the script output.

Will prove useful when dealing with problems, having to "upgrade" the script, etc.

Your PHP code would become something like:

if (isset($_POST["field"]) && isset($_POST["value"])) {

  $field = cleanStr($_POST["field"]);
  $value = cleanStr($_POST["value"]);

  $q = $dbc -> prepare("SELECT ".$field." FROM accounts WHERE ".field." = ?");
  $q -> execute(array($value));

  $msgType = "error";

  switch($field) {

    case "email": {
      if (!filter_var($value, FILTER_VALIDATE_EMAIL)) {
        $message = "This is not a valid email!";
      } elseif ($q -> rowCount() > 0) {
        $message = "Email already owns an account!";
      } else {
        $message = "Email success!";
        $msgType = "success";
      }
    }
    break;

    case "password": {
      if (strlen($_REQUEST['password'])  rowCount() > 0) {
        $message = "Username already taken";
      } else {
        $message = "Username available!";
        $msgType = "success";
      }
      break;
    }

    default:
      echo "The field could not be identified!";
      break;
  }

  echo ''.$message.'';

} else {
  header('Location: http://www.projectv1.com');
  exit();
}

function cleanStr($str) {
    return filter_var(trim($str),FILTER_SANITIZE_STRING);
}


The above notes should give you an overall improvement on your form validation, leading to a valid code and a better solution for future maintenance.

I haven't tested any of it, but it should be working.

Validating Code:

This links should prove useful as to validate your code and warn you about common mistakes:

  • HTML: Validating HTML using the W3C Ma

Code Snippets

<form id="myForm" action="#" method="post">
  <fieldset>
    <legend>Login Details</legend>
    <label>Your Email:</label>
    <input id="email" name="email" type="text" />
    <label>Password:</label>
    <input id="password" name="password" type="password" />
  </fieldset>
  <fieldset>
  <legend>Account Details</legend>
    <label>Your Username:</label>
    <input id="username" name="username" type="text" />
  </fieldset>
  <p>
    <input class="submit" type="submit" value="Create Account" />
  </p>
</form>
$('#myForm input').blur(function() {

  var id = $(this).attr("id");
  $('#' + id).after('<div class="loading"></div>');

  $.post('http://www.example.com/ajax.php', {field:id, value:value}, function (response) {
    $('.'+id+'.msg').hide();
    setTimeout(function() {
      $('.loading').remove();
      finish_ajax (id, response);
    }, 1000);
  });

});

function finish_ajax (id, response) {
  $('#' + id).after(response).fadeIn(2000);
}
if (isset($_POST["field"]) && isset($_POST["value"])) {

  $field = cleanStr($_POST["field"]);
  $value = cleanStr($_POST["value"]);

  $q = $dbc -> prepare("SELECT ".$field." FROM accounts WHERE ".field." = ?");
  $q -> execute(array($value));

  $msgType = "error";

  switch($field) {

    case "email": {
      if (!filter_var($value, FILTER_VALIDATE_EMAIL)) {
        $message = "This is not a valid email!";
      } elseif ($q -> rowCount() > 0) {
        $message = "Email already owns an account!";
      } else {
        $message = "Email success!";
        $msgType = "success";
      }
    }
    break;

    case "password": {
      if (strlen($_REQUEST['password']) < 6) {
        $message = "Your password is not long enough.";
      } else {
        $message = "Password success!";
        $msgType = "success";
      }
    }
    break;

    case "username": {
      if (strlen($_REQUEST['username']) < 3) {
        $message = "Has to be at least 3 characters";
      } elseif ($q -> rowCount() > 0) {
        $message = "Username already taken";
      } else {
        $message = "Username available!";
        $msgType = "success";
      }
      break;
    }

    default:
      echo "The field could not be identified!";
      break;
  }

  echo '<div class="'.$field.' msg '.$msgType.'">'.$message.'</div>';

} else {
  header('Location: http://www.projectv1.com');
  exit();
}


function cleanStr($str) {
    return filter_var(trim($str),FILTER_SANITIZE_STRING);
}

Context

StackExchange Code Review Q#4925, answer score: 3

Revisions (0)

No revisions yet.