Regula is an annotation-based form-validation framework written in Javascript. There already exist a few frameworks that address form-validation in Javascript, but I have found them to be somewhat lacking. I have thought about writing one of my own for some time, but I honestly had no idea what form it would or should take. I knew that I wanted to make one that was easy to use, flexible, and easily extensible (custom validation rules). I finally got an idea as to the form my framework should take, when I was looking at Hibernate bean-validation. I like the fact that you can set constraints by using annotations like @NotNull or @NotEmpty. That way, when you look at the bean, you are immediately aware of the constraints attached to it. I wanted to do something similar in HTML.

Enter HTML5. HTML5 supports and endorses custom attributes in HTML tags. Purists may scream "No!", but I think it is a useful feature. However, like all features it has the potential for abuse. But that’s another topic entirely. Anyway, I started thinking - what if I could use a custom attribute to specify the constraints? Then I could use Javascript to identify those constraints and then enforce them during validation. What I was thinking of, was to do something like this:

[/sourcecode]

That bit of code describes a text box which cannot be empty, and which expects a numeric value between 1 and 5. With this basic design in mind, I started working on my framework. It took me about a week of on-and-off work (maybe 3 days actual work) but I’ve come up with something that is, in my humble opinion, a flexible and easy to use framework. I plan to document the use of this library/framework more thoroughly, but this post should serve as a gentle introduction to the framework and its features.

In *Regula* (which, by the way, means "rule" in Latin) form elements (input elements or even the form elements) can have constraints attached to them in a similar fashion to the example I described earlier. There is a small difference, however:

[/sourcecode]

As you can see, I use a class name of regula-validation which tells the framework that this input element has constraints attached to it. The reason I did this was for efficiency reasons. It’s much more efficient to grab all elements that have a class name of regula-validation than walking the whole document tree to search for nodes that have a data-constraints attribute.

After you annotate the input elements with their constraints, you’re halfway there already! All you have to do after that is add a script tag for the framework:

[/sourcecode]

And then add the necessary Javascript to validate the form (example uses jQuery):

jQuery(document).ready(function() { // must call this first. The best place would be in an // onload handler. This function looks for elements with // a class name of "regula-validation" and binds the // appropriate constraints to the elements regula.bind();

jQuery("#myForm").submit(function() {
    // this functions performs the actual validation
    var validationResults = regula.validate();
        for(var index in validationResults) {
             var validationResult = validationResults[index];
             alert(validationResult.message);
        }
    });
});
[/sourcecode]

That’s pretty much all there is to it. More advanced uses of the framework don’t deviate that much from this pattern. Compared to other form-validation frameworks (that I’ve seen), validation will not stop on the first failing element. The validate function runs through every input element and validates it against the constraints bound to that element, and returns an array of "validation results". Each "validation result" element in the array has the following properties:

  • *constraintName* - the name of the failing constraint

  • *custom* - a flag that says whether this is a custom constraint or not

  • *constraintParameters* - An array of objects that represents the parameters passed to this constraint (defined in the HTML. For example @Max(max=5), where you have a parameter who’s name is max and who’s value is 5. There’s a little more to this, but like I said, this is supposed to be a gentle introduction :))

  • *receivedParameters* - A hash (organized such that the name of the parameter is the key, and the value is well, the value) of parameters that the validator function received (helpful when you have a custom validator).

  • *failingElements* - An array containing references to the actual input element or elements (in the case of form-specific constraints) that failed the constraint.

  • *message* - The error message.

This may all seem like a bit too much, but trust me. It’s pretty simple! I designed the framework so that it performs all the validation and provides the result, but leaves the handling of the errors to the developer. Currently, the framework supports 13 14 built-in constraints, which are:

  • *@Checked* - Enforces the constraint that a checkbox or a radio button must be checked.

  • *@Selected* - Enforces the constraint that a select box must be selected. Right now, it checks for this by looking at the selectedIndex property. If it is zero, it assumes that the box is unselected. The reason I’ve done this is because in most cases select boxes have a "Please select a value" option at the very top. I’m open to suggestions if anyone thinks this is not a good idea.

  • *@Max(max=n)* - Enforces the constraint that a field (technically speaking, the value of a field) can only hold a number that is less than or equal to n.

  • *@Min(min=n)* - Enforces the constraint that a field (technically speaking, the value of a field) can only hold a number that is greater than or equal to n.

  • *@Range(max=n, min=m) or @Between(max=n, min=m)* - Enforces the constraint that a field (technically speaking, the value of a field) can only hold a number that is less than or equal to n and greater than or equal to m.

  • *@NotEmpty* - Enforces the constraint that a field cannot be empty.

  • *@Empty* - Enforces the constraint that a field must be empty.

  • *@Pattern(pattern=/regexp/) or @Matches(pattern=/regexp/)* - Enforces the constraint that a field must match the the regular expression regexp.

  • *@Email* - Enforces the constraint that the field must contain a valid email.

  • *@IsAlpha* - Enforces the constraint that the field can only contain letters (A-Z and a-z).

  • *@IsNumeric* - Enforces the constraint that the field can only contain numbers (0-9).

  • *@IsAlphaNumeric* - Enforces the constraint that the field can only contain letters and numbers (A-Z, a-z, and 0-9).

  • *@CompletelyFilled* - Enforces the form-specific constraint that all fields in the form must be filled.

  • *@PasswordsMatch(field1="id_of_first_password_field", field2="id_of_second_password_field")* - Enforces the constraint that the values of the password fields specified, must match.

As you can see, some constraints take parameters. In addition to those parameters that have been defined (or have not been defined - for constraints that don’t take any) there are two optional parameters called msg or message, and name label. These attributes let you specify custom error message. Without these attributes, the validation framework will return generic error message. For example, let us say that you wanted to ensure that a person’s age is greater than 21. You could do something like this:

Age: [/sourcecode]

If you do this, the error message returned from the validation will say You need to be older than 21! rather than returning a generic message like The field value needs to be greater than 21. Now what about the name label parameter? Well, that lets you customize the message even further. The example I provide may seem a bit contrived, but that’s because I’m using the built-in validators. They make more sense when applied to custom validators (coming up later!):

Age: [/sourcecode]

In this example, the error message will say Your cat needs to be older than 21!. Also notice that I didn’t explicitly say "21" either. When you enclose something in curly braces, the validator will try to interpolate or substitute the value using a parameter value that you have provided. Like I said, this makes a bit more sense in custom validators!

*Note: * It occurred to me while writing this that I should probably change name to label because that better describes what I’m trying to do. I’ll update my code to reflect that.

A feature that I’ve felt is lacking in other form-validation frameworks, is the ability to add custom constraints. Adding custom constraints in *Regula* is very easy. Assuming I want to add a constraint called @MustBeVivin which enforces the constraint that the value of a text field must either contain the word "Vivin" or "Awesome", I would do something like this:

jQuery(document).ready(function() { regula.custom({ name: "MustBeVivin", defaultMessage: "{label} must be equal to \"Vivin\" or \"Awesome\"", validator: function() { return this.value.toLowerCase() == "vivin" || this.value == "awesome"; } });

    //Notice that custom constraints need to be defined before
    //you call bind()
    regula.bind();
[/sourcecode]

Now, in HTML I can say:

Enter a name:

Enter a word: [/sourcecode]

When the validation runs, the fields will fail the constraint if they don’t contain the word "Vivin" or "Awesome", and depending on which field failed, you will get The name must be equal to "Vivin" or "Awesome" or you’ll get The word must be equal to "Vivin" or "Awesome". This is useful if you define a custom constraint that is used in many places, but you want to be able to customize the error message as well. On another note, you could also do[.line-through]# @MustBeVivin(name="The word", message="The bird is {name}")# @MustBeVivin(label="The word", message="The bird is {label}") in which case you’ll get The bird is The Word. If you define a message parameter in the constraint definition, it will override the default message.

When you define custom constraints, you can also define parameters for it. For example:

jQuery(document).ready(function() { regula.custom({ name: "FooBarConstraint", defaultMessage: "{label} and {foo} and {bar}", params: ["foo", "bar"] validator: function(params) { var foo = params["foo"]; var bar = params["bar"];

/* do some validation */
       return booleanResult;
    }
});
    regula.bind();
[/sourcecode]

In the above example, I am defining a constraint called FooBarConstraint that accepts two parameters called foo and bar. So, in HTML you’d define it like so: @FooBarConstraint(foo="blah", bar=5). Pretty simple, right?

There is one more thing I haven’t gone over. Well, actually, there are quite a few things I haven’t gone over really well, but like I mentioned before…​ gentle introduction and all ;). Anyway, so one more thing that I need to go over is a form-specific constraint. These are constraints that apply to a form as a whole. For example, earlier I talked about the @CompletelyFilled constraint that ensures the form is completely filled. You can also create your own form-specific constraints. The way you create them is almost exactly the same as a regular constraint, except for one thing. The validator does not return a boolean. Instead, it must return a list of elements that failed the constraint. For example, assume that I wanted to create a constraint called @PasswordsMatch, which ensures that the passwords entered in the form match. I could do something like this in HTML:

<form id = "myForm" class="regula-validation" data-constraints="@PasswordsMatch">
  Password: <input id="password1" type="password" data-constraints="@NotEmpty" /> <br />
  Re-enter password: <input id="password2" type="password" data-constraints="@NotEmpty" /><br />
</form>

And do the following in Javascript:

regula.custom({ name: "PasswordsMatch", formSpecific: true, defaultMessage: "Both your passwords must match!", validator: function() { var failingElements = [];

if(document.getElementById("password1").value != document.getElementById("password2").value) {
    failingElements = [document.getElementById("password1"), document.getElementById("password2")];
}
        return failingElements;
    }
});
[/sourcecode]

As you can see, the validator returns an array of failing elements. If the array is empty, it means that the validation was successful. Notice the formSpecific attribute. This tells the framework that the custom constraint is a form-specific constraint. The validator is smart enough to complain if you attach a form-specific constraint to an input element, or vice-versa.

The above information is out of date. The @PasswordsMatch(field1="id_of_first_password_field", field2="id_of_second_password_field") is now a built-in constraint in Regula

This should give you basic knowledge about the Regula framework. I haven’t gone into as much detail as I would have liked; I need to write up some comprehensive documentation. If you’d like to play with the framework (and I encourage it!) you can get it from GitHub or download it directly from /api/media/5e9b98e5-60e1-453c-bce0-8fa1f5bcadf4/content].

On another note, I’m aware that using JSF (and things of that nature) it is possible to do client-side validation along with server-side bean-validation. But this is not the case in other languages and stacks (PHP for example). My aim is to provide a simple and powerful form-validation framework. In addition, I want to see if I’m able to work this into JSF, Spring, or Groovy on Grails (a really long-term goal - something I’d like to look at if/when I have time).

I look forward to your comments and suggestions for improvement. Thank you in advance for your feedback!

Update: I’ve made a few changes to the library (you can see the strikeouts and notes in the post). You can get v1.0.0 at GitHub.