If you are using home-grown client-side validation, stop immediately. Take 15 minutes to grab a validation plugin such as the jQuery Validation Plugin. It already takes care of a lot of cases you haven’t yet realized you need. The purpose of this post is not to introduce the plugin, so I will now dive in and assume the reader is already using the jQuery validation plugin.
The plugin has remote validation built right in. For example, say you have a user-registration page, and you want to make sure that the email address the user supplies is not already taken. The documentation gives the following example code:
1 2 3 4 5 6 7 8 9
Now when validation is triggered, it will make sure that the email field is there (required), that is of valid email format (email), and then once those are done, it will make a remote call to check-email.php. That php file will get a request parameter called “email” with a value such as “firstname.lastname@example.org”. It should return a JSON
true if the provided email is valid. If the email is invalid, it can either return
false or an error message to display to the user.
Advanced Remote Methods
Often the previous example is exactly what you need, and it is great that the plugin makes the usual case so easy. But what if remote validation of one field is dependent on another? Let’s say we have a page on which the user can order products. It has two
<select> elements. One lets you pick a product, and the other lets you pick the timeframe in which you will need the product. So, a user might say
I need an Easy Bake Oven in 4-6 weeks.
We want to setup remote validation that checks that a product will be available in that timeframe. (This is a contrived example. Let’s ignore the user experience issues present n it.) Since the
remote validation method accepts any arguments the jQuery
ajax method accepts, a first pass at this is fairly straightforward.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
Now check-timeframe.php will get two request parameters:
timeframe. We are explicitly adding
product as a request parameter to the AJAX call. On the other hand,
timeframe is added by the
remote method of the validation plugin, because it is the field being validated.
This does almost exactly what we want it to do. But what happens when the user picks a timeframe but doesn’t pick a product? The product field is marked as required, so the user will get an error message for it. Your remote validation for timeframe will still fire (because the user did pick a value for timeframe), but check-timeframe.php won’t get any value for
product. While it depends on your implementation, this will most likely result in an error message something like ”product is required”. So now the user is getting 2 error messages for forgetting to pick a product. What we really want is a way of only making the remote call for
timeframe if a
product is chosen.
Custom Remote Methods
We can add a method to the validator that delegates to the remote method, but only if certain conditions are met.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
Now the validator has a method called
productInTimeframe. The argument to this method is an object with a
product attribute that can be either a value or a function that will return the relevant value. If that product isn’t there, it says
My dependencies aren’t satisfied, so I can’t do my validation. You better check out those dependencies first and then we can talk.
It is easy to update our form validation to use this new method:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
Now the user won’t get two error messages for forgetting to select a product. If he does select a product, the usual remote validation will occur, and if the product isn’t available in the selected timeframe, the
timeframe select will show an error.
Hide the Details
This approach is a bit more verbose than simply using the built-in remote method, but it is the best way I have discovered to deal with this sort of scenario. Also, it is notable that the verbosity is contained within the
productInTimeframe method itself. The arguments we are providing to the
validate method for our form have actually been simplified. I think it is nice to have a reusable method that hides the details of the remote call.