Some tricky bits in in-browser form mangling and validation

June 13, 2012

In the process of writing client side JavaScript to modify and validate forms, I've run into a number of tricky bits and gotchas. In my usual tradition I'm going to write them down here, if only so that I can look them up again in a year or two when I've forgotten them all again.

Like many web apps, ours has a core (server-side) form processing flow where we first display the initial blank form, then on form submission we validate it and if there are any errors we re-display the form with your submitted values filled in and any error messages showing. Repeat as many times as necessary until you either give up or submit a fully valid form. Our forms also have the common 'reset form to initial values' button; on the initial form the browser will blank all fields, and otherwise it resets the field values to their initial (potentially erroneous) state and values. In general, most of the complications in client side form handling are ultimately caused by these intermediate 'submitted and redisplayed with errors' forms.

The first gotcha is the proper interaction of client side validation with form resets. On form reset, what you need to do is not blank out any error messages or 'that's good' notes you're showing, but restore the initial value of the status area. This is because you may be handling an intermediate form submission where the field had an error and thus the status area started out showing a (server side generated) error message. Since form reset restores the erroneous field value, you also need to restore the error message to go with it.

(There are various techniques for saving the initial error messages, ranging from doing it in JavaScript to simply changing a CSS style to hide them. I saved the HTML text in a JS variable because I'm a programmer.)

The next gotcha is the issue of hiding a form field that isn't currently applicable to the state of the form; for example, hiding a field for the graduate student number if the person requesting an account isn't a graduate student. There are two complications.

To start with, the rule for hiding fields is that you can't hide a form field that has an error (unless you know that your server side validation will ignore the field on form submission because it's not applicable). If you aren't doing client side validation of the field, this is based on the initial presence or absence of an error message (which may be inapplicable to the current state of the field, but it's the best you can do); if you are doing client side validation you can use the current state of the field if you have a valid result.

(If field validation requires a server callback you may not have valid results right now.)

Next, the existence of redisplayed forms means that you need to check the initial state of the form before hiding (or revealing) fields. For example, you could be redisplaying an incomplete account request form where the person's indicated that they're a graduate student; in that case, you definitely don't want to automatically hide the graduate student number field. Form resets complicate this further because the straightforward way of hooking into them happens before the form reset, so you will see the current value of the fields instead of the original value that you need to decide what to show or hide for the after-reset form state.

(The straightforward way of hooking into form reset is to attach to the click event for any type="reset" form field. Possibly there is a better way.)

PS: unless you're familiar with the tricky bits in this sort of stuff (and confidant that you're going to stay that way), I heavily recommend leaving yourself comments in the source code about them. This is probably not an issue for people who program client side JavaScript all the time, but I'm probably always going to be a periodic dabbler in this area.

Sidebar: On server side validation of inapplicable form fields

You might think that of course the server shouldn't bother validating form fields that are inapplicable given the other options that you've picked in the form. There are two problems with this. First, as a pragmatic matter many server side form validation frameworks simply don't do this. They validate fields bottom-up, first checking that the individual fields pass validation independently and only then letting you validate the entire collection of fields together. By the time you get control of the validation process an inapplicable field may already have failed its own basic validation.

(This is certainly the case with Django's form handling.)

Second, even as a theoretical matter this would clearly be a more complex approach because you now have to specify the interdependencies between fields (in some way short of writing fully custom form validation code for each form). There are all sorts of possible interdependencies and complexities here; you probably can't support them all and even supporting some of them gets you into an increasing mess of complexity. And you're doing all of this to your framework to support a rare case (when an inapplicable field has invalid content; normally an inapplicable field will be untouched).

On the whole it's much simpler for a framework to not try to support this with general code but instead just provide a way to let the programmer fully take over form validation themselves.

Written on 13 June 2012.
« Client side form validation can let people explore their options
How the Linux kernel divides up your RAM »

Page tools: View Source, Add Comment.
Login: Password:
Atom Syndication: Recent Comments.

Last modified: Wed Jun 13 15:33:07 2012
This dinky wiki is brought to you by the Insane Hackers Guild, Python sub-branch.