Developing User Friendly Forms | Sitegeist | Splat Productions

Developing User-Friendly Forms: Get Validation

TwitterLinkedIn

Developing user-friendly forms that look good in a variety of browsers is a thankless job. Form elements are notoriously inconsistent across browsers.  But getting the design right is only half of the battle. It’s equally important to make sure you’re getting the right information and providing a quality user experience that also satisfies business goals, making everyone happy.

What is a quality user experience with regard to web forms? Users like web forms that are forgiving. A form shouldn’t bark at you when you enter your phone number, say, with dots instead of dashes. It’s nice when forms give you a summary of the fields you need to correct rather than making you hunt around for the offending fields. Longer forms that are spread across multiple pages with breadcrumbs that allow you to go back are preferable to one big page that scrolls down endlessly. These kinds of design oversights make users unhappy because they expect more from web applications. On the other hand, some users will try to fill out as little as possible, and still others will spam you or try to hack your site, so it’s important to have validation in place.

There are two ways to go about validating web forms. I have touched upon client-side validation, which involves making sure the user has entered all the required fields in the right format before a form is submitted. Client-side validation is done with Javascript or a shorthand libary like jQuery. Google uses Javascript and AJAX on all of its forms to give you live feedback before you’ve submitted a form. In addition to being helpful to the user, this helps Google minimize bandwidth-taxing calls to the server. The next step is server-side validation. Client-side validation is nice, but server-side is essential. If you’re writing to a databse, this step is indispensable from a security standpoint. Server-side validation gives you the opportunity to clean up the data and reformat it before doing something with it, and it ensures that users with Javascript turned off are getting the same experience. I’m going to show you really basic examples of both approaches in the context of a WordPress site.

Let’s start with an example of server-side validation using some basic PHP. We’re going to collect four fields: A name, a state, an email address and a phone number. This is what the bare-bones form looks like:

[xml]
<form action="<?php the_permalink(); ?>" method="post">
<label for="full_name">Name</label> <input type="text" name="full_name" value="" />
<label for="state">State</label>
<select>
<option value="">MD</option>
<option value="">PA</option>
<option value="">NJ</option>
<option value="">NY</option>
</select>
<label for="email">Email</label> <input type="text" name="email" value="" />
<label for="phone">Phone</label> <input type="text" name="phone" value="" maxlength="10" />
<button type="submit">Submit</button>

<!– hidden field used to determine if the form has been submitted –>
<input type="hidden" name="submitted" value="true" /></form>
[/xml]

You’ll notice that there is a hidden field at the end which will be used to tell us if the form has been submitted. You can tell by the form’s action attribute that this is a self-referencing form. We’re going to use some conditional logic to determine if the form has been submitted at the top of the document. If it has been submitted we can begin validating the data and building an email message. If there are errors the user will be presented with the form again and a summary of errors. Correctly entered fields will be pre-filled. From the top, assuming the form has been submitted and all the fields are required, we’re going to validate the post data, flagging errors and adding them to an array of unique error messages:
[xml]
<?php
if(isset($_POST[‘submitted’])) {
if(trim($_POST[‘full_name’]) === ”) {
$hasError = true;
$errors[] = "Enter your name.";
} else {
$full_name = trim($_POST[‘full_name’]);
}
if(trim($_POST[‘state’]) === ”) {
$hasError = true;
$errors[] = ‘Enter your state.’;
} else {
$state = trim($_POST[‘state’]);
}

if(trim($_POST[’email’]) === ”) {
$hasError = true;
$errors[] = ‘Enter your email address.’;
} else if (!preg_match("/^[[:alnum:]][a-z0-9_.-]*@[a-z0-9.-]+.[a-z]{2,4}$/i", trim($_POST[’email’]))) {
$hasError = true;
$errors[] = ‘Enter valid email address.’;
} else {
$email = trim($_POST[’email’]);
}

if($_POST[‘phone’] === ”) {
$hasError = true;
$errors[] = ‘Enter your phone number.’;
} else {
$phone = $_POST[‘phone’];
}
?>
[/xml]

The PHP function trim() gets rid of extra whitespace before determining whether a field was left blank. The function preg_match() compares the email entered to a regular expression, making sure that it conforms to the conventions. In the event that your post data is destined for a MySQL database, it’s best to escape out special characters with htmlspecialchars() and/or mysql_real_escape_string()The next bit of code checks if there was an error. If not, we can go ahead and build an SMTP authenticated email using WordPress’s built-in functions.
[xml]
<?php
if(!isset($hasError)) {
$emailTo = get_option(‘tz_email’);
if (!isset($emailTo) || ($emailTo == ”) ) {
$emailTo = get_option(‘admin_email’);
}
$subject = ‘Inquiry from ‘ . $full_name;
$body = "Name: $full_name nState: $state nEmail: $email nPhone: $phone";
$headers = ‘From: ‘ . $full_name . ‘ <‘ . $emailTo . ‘>’ . "rn" . ‘Reply-To: ‘ . $email;
wp_mail($emailTo, $subject, $body, $headers);
$emailSent = true;
}

}
?>
[/xml]

If the email has been sent successfully, we show the thank you page. You can accomplish this however you’d like. In the case that the email wasn’t sent successfully, we show a summary of errors in a div that will be positioned somewhere near our form:
[xml]
<?php
if(isset($emailSent) && $emailSent == true) { ?>

/* HTML for the thank you page goes here */

<?php } else if(isset($emailSent) && $emailSent == true) { ?>
<!–HTML for the thank you page goes here–>
<?php } else if(isset($hasError)) { ?>

<div class="error_summary">
<h3>Please correct the following</h3>

<ul>

<?php foreach($errors as $error) {
echo ‘<li>’ . $error . ‘</li>’;
}
?>

</ul>

</div>

<?php } ?>
[/xml]

Here we’re creating an unordered list that displays all the error messages we added to the array $errors earlier. Then we’re going to show the form again with the correct fields already filled in for the user. We can accomplish this by conditionally showing the appropriate post data in the value attribute of the inputs. It’s slightly different for select elements, where we’ll be conditionally setting the selected attribute to, you guessed it, “selected”. Here’s the updated form from earlier:
[xml]
<form action="<?php the_permalink(); ?>" method="post">
<label for="full_name">Name</label>
<input type="text" name="full_name" value="<?php if(isset($_POST[‘full_name’])) echo $_POST[‘full_name’];?>" />
<label for="state">State</label>
<select>
<option selected="selected" value="">" >MD</option>
<option selected="selected" value="">" >PA</option>
<option selected="selected" value="">" >NJ</option>
<option selected="selected" value="">" >NY</option>
</select>
<label for="email">Email</label> <input type="text" name="email" value="<?php if(isset($_POST[’email’])) echo $_POST[’email’];?>" />
<label for="phone">Phone</label> <input type="text" name="phone" value="<?php if(isset($_POST[‘phone’])) echo $_POST[‘phone’];?>" maxlength="10" />
<button type="submit">Submit</button>

<!– hidden field used to determine if the form has been submitted –>
<input type="hidden" name="submitted" value="true" />
</form>
[/xml]

There’s definitely a smarter way to check which state was selected using arrays, but I’ve kept it simple for the purposes of this example. That about does it. As long as there is an outstanding error, the form is shown with the error messages. This web form could stand to benefit from a little client-side validation. Using the same form and the jQuery validate plugin we can set up a system of checks to flag errors before they get to the server. Since we’re working within WordPress, we first need to enqueue jQuery and the validate plugin in our functions file. Check with the codex for details on that, but essentially, you’re going to be calling upon the wp_enqueue_script() function in your functions file. Here is the basic form we’re working with:
[xml]
<form id="homeForm" action="<?php the_permalink(); ?>" method="post">
<label for="full_name">Name</label> <input type="text" name="full_name" value="" />
<label for="email">Email</label> <input type="text" name="email" value="" />
<label for="phone">Phone</label> <input type="text" name="phone" value="" maxlength="10" />
<button type="submit">Submit</button>
<input type="hidden" name="submitted" value="true" />
</form>
[/xml]

At the bottom of the document, just before the close of the body tag, we set up the client-side validation rules. As in the previous example, we’re taking the approach of presenting the user with a summary of errors, but this time around the validation is bound to a change event, giving the user immediate feedback when they have fixed an error. I’ll explain this code line by line below.
[xml]
jQuery(document).ready(function() {
$(‘<div id="errorSummary">Please correct the following errors:</div>’).append().hide().insertAfter("form");
$(‘#homeForm’).validate({
highlight: function(element, errorClass) {
$(element).addClass("invalidElem");
},
unhighlight: function(element, errorClass) {
$(element).removeClass("invalidElem");
},
errorContainer: "#errorSummary",
errorLabelContainer: "#errorsList",
wrapper: ‘li’,
errorElement: "div",
rules: {
full_name: "required",
state: "required",
email: "required",
phone: "required"
},
messages: {
full_name: "Enter your name.",
state: "Enter your state.",
email: "Enter a valid email address.",
phone: "Enter your phone number."
}
});
$(‘input’).change(function(e) {
$(‘form’).validate().element($(e.target));
});
});

[/xml]

First I set up a container for the error messages that is appended to the end of the form and initially hidden. (Note: Using an error summary actually makes the most sense when you don’t have the flexibility to add elements to the document, such as when you’re absolute positioning elements.) Next I call the validate function. The highlight option lets us add a CSS class to the offending element via an anonymous function. Likewise for the unhighlight option; here we’re removing the CSS class when the proper data has been entered. The goal here is to insert error messages into an unordered list contained by a div, which we set up at the outset. The following four options are used in conjuction to achieve just that: errorElement specifies the type of container element (the default is label). errorContainer specifies the selector that is made visible when there are errors. errorLabelContainer specifies the class associated with individual error messages, and wrapper specifies which type of element to insert those messages into.

That covers the presentation. The next option, messages, lets us specify unique error messages for each error. Finally, the last lines bind the change event to all inputs, firing the validate function on the element in question to provde the user with immediate feedback.

There are many ways to use the validate plugin and many more options at your disposal; it’s a robust plugin that has thought of everything for you. In this example I have applied the validation rules via the element names, full_name, email and phone. You could also apply validation rules via classes, element attributes, or the elements themselves. With a combination of granular client- and server-side validation, you’ll be getting the right data the first time, users will feel validated, and no one gets hurt.

Post Navigation