52

Our web forms are really complex. What's a great solution for extensible form validation, preferably one that works with jQuery?

Background:

Our site has a bit of Ajax, but the real focus is on user experience through about 20 multi-page forms or "wizards." These forms are complicated.

  • Presentation: Some fields are floats or ints. Validation means stripping non-decimal characters, but we also want to make sure that, if a user enters 5 into a price field, the field is updated to 5.00.
  • Side effects: Some fields have side effects when updated. E.g., updating the price or quantity of an item needs to update a subtotal field.
  • Widget-driven elements: Some fields are hidden and have values populated by widgets. E.g., a map widget lets you point to a location and a hidden field is updated with latitude-longitude coordinates, but the location must be within a certain region.
  • Groups: Some fields are groups, like address/city/state/zip, and should only be validated when all of the fields have bee populated.
  • Server-side validation: Validation of some fields requires back-end checking via Ajax requests
  • Multiple forms per page: Sometimes a user needs to fill out one form before a dialog opens with another form. A framework has to be more versatile than binding to onSubmit — we sometimes post multiple forms in order from the same page using Ajax. (E.g., we let users sign up and create a widget in one swoop but, due to legacy systems, that flow requires two POST requests.)
  • Customizable error display: Sometimes errors appear above fields, sometimes the field style changes, and our new designs call for tooltip-like popups (ala qTip) for some errors.
  • Snappiness: User experience is key and tactile feedback is important. Any solution
  • Submit buttons: Clicking the submit button needs to validate everything and then show a response — but since some of the validation happens asynchronously.

We're currently using the jQuery Validation library but our forms appear to be outgrowing its capability. I've been looking at things like <angular/>, Knockout and Backbone.js, but I'm worried that they're too heavyweight or that they would require us to rewrite our frontend.

(This should be a community wiki.)

a paid nerd
  • 30,702
  • 30
  • 134
  • 179
  • I'm curious about what's really behind this statement, _"our forms appear to be outgrowing its [jQuery Validation Plugin] capability"_. Can you explain? Lots of people use it, so providing more detail about these supposed limitations could be very educational to others. – Sparky Mar 15 '12 at 22:40
  • It's been more than a year since we ditched it, so I can't remember the whole story. I remember having bugs with IE7 (which 7% of our users still use). The setup code is much more verbose and spaghetti than with jQuery Tools. jQuery Tools' error and tooltip customization is far easier and, in general, has a good API and good documentation. It's also easier to integrate XHR-based validation into the form flow with jQuery Tools. – a paid nerd Mar 15 '12 at 23:52
  • try valijate jquery plugin. seems promising. here is the complete guide for using that plugin. http://valijate.com/Docs.php – bula May 29 '17 at 07:40

8 Answers8

55

This is a shameless plug, but might I volunteer a framework that I designed? I've built it based on annotations (a la Hibernate Validator). It has support for custom constraints and I feel that it is pretty powerful. Here is also a Stackoverflow question where I asked for a review of the framework.

  • Presentation: With custom validation-constraints, you can bind validation to the onChange element. Also, because Regula supports custom validators, you can have your custom validator update the value of a field (so change 5 to 5.00).
  • Side effects: Regula supports side-effects via custom constraint-validators.
  • Groups: Regula supports validation groups. You can target specific groups for validation. By combining a custom validator and a group, you can control the behavior of the validator so that it validates only when all elements of that group are filled (you would have to perform this check via normal Javascript though).
  • Server-side validation: With custom-constraints, you can make an AJAX call to perform server-side validation. With the way the framework is structured currently, this necessarily has to be a blocking ajax-call. I plan on adding an asynchronous feature in the future.
  • Multiplee forms per page: Regula isn't limited to validating one form per page. It can handle multiple forms (not sure if I understood your requirement correctly - so I might not have answered this part correctly).
  • Customizable error display: Regula doesn't do anything to the UI of the page as far as validation is concerned. When you validate, you get a set of constraint violations that contain error messages and such. It is up to you, how to display them.
  • Snappiness: I haven't performed any benchmarks, so I cannot comment as to my framework's performance in this regard.
  • Submit buttons: This is something I have yet to solve (asynchronous vs. synchronous).

Here are a few examples:

The following shows standard validation, with built-in constraints:

<input id = "myInput"
       name = "myInput"
       type = "text"
       class = "regula-validation"
       data-constraints = '@NotEmpty @IsNumeric @Between(min=1, max=5)' />

jQuery(document).ready(function() {
    // must call regula.binnd() 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 function performs the actual validation
        var validationResults = regula.validate();

        for(var index in validationResults) {
             var validationResult = validationResults[index];
             alert(validationResult.message);
        }
    });
});

As you can see, you're only working with constraint violations, and so the manner in which you display the error message is entirely up to you.

Here's an example of a custom constraint:

regula.custom({
   name: "MustBe42",
   defaultMessage: "The answer must be equal to 42",
   validator: function() {
      return this.value == 42;
   }
});

And its use:

<input id = "theAnswerToLifeTheUniverseAndEverything" 
       name = "theAnswerToLifeTheUniverseAndEverything" 
       value = ""
       class = "regula-validation"
       data-constraints = "@MustBe42" />

Since the validator is a Javascript function, you can have it do anything (so this addresses your question about side effects).

Here is an example of another constraint that accepts parameters:

regula.custom({
   name: "DivisibleBy",
   defaultMessage: "{label} must be divisible by {divisor}",
   params: ["divisor"],
   validator: function(params) {
      var divisor = params["divisor"];
      return (this.value % divisor) == 0;
   }
});

And usage:

<input id = "number" 
       name = "number" 
       value = ""
       class = "regula-validation"
       data-constraints = "@DivisibleBy(divisor=3, label='The Number')" />

Here is an example of using validation groups:

<input id = "score"
       name = "score"
       type = "text"
       class = "regula-validation"
       data-constraints = '@IsNumeric(label="Score", 
                                      message="{label} needs to be a number!"
                                      groups=[FirstGroup, SecondGroup, ThirdGroup]' />

<input id = "age"
       name = "age"
       type = "text"
       class = "regula-validation"
       data-constraints = '@IsNumeric(label="Age", 
                                      message="{label} needs to be a number!"
                                      groups=[SecondGroup]' />

<input id = "name"
       name = "name"
       type = "text"
       class = "regula-validation"
       data-constraints = '@NotEmpty(label="Name", 
                                     message="{label} cannot be empty!"
                                     groups=[FirstGroup]' />

And a snippet that validates only FirstGroup (so only score and name are validated):

var constraintViolations = regula.validate({groups: [regula.Group.FirstGroup]});
var messages = "";

for(var index in constraintViolations) {
      var constraintViolation = constraintViolations[index];
      messages += constraintViolation.message + "\n";
}

if(messages != "") {
   alert(messages);
}

If you're planning on trying it out, I recommend downloading version 1.1.1. The current documentation matches that version specifically. In 1.2.1 I added support for compound constraints, but I haven't updated my documentation to reflect that.

I understand if this doesn't address all your concerns, or if this is not what you are looking for. I thought I'd just put it out there. Also, if you do check it out then I will make sure to update the documentation to reflect version 1.2.1. I've been busy with school and work and so I haven't had the time to do that.

UPDATE #1

Sohnee mentioned client-side validation. I'm actually working on an integration between Regula and Spring 3. Hopefully I should be able to release it sometime soon (depending again, on work and school). The integration works by translating Hibernate validation-constraints to Regula validation-constraints. This way, you only have to write validation code once (mostly). For custom constraints though, you will still have to write code on the Javascript side (the custom validator). But once you annotate code on the server-side with Hibernate validation-constraints, you don't need to do anything on the client-side; those constraints automatically get applied to form elements on the client-side.

Matthew Abbott has also been able to integrate Regula with ASP.NET MVC.

UPDATE #2

I've got a demo webapp (mavenized) on github that showcases the integration between Regula and Spring 3.0.x Web MVC using Hibernate Validator. It's not really documented or anything, it's more proof-of-concept. I plan to add some documentation to the github page about the integration and how it works.

UPDATE #3

I've updated the documentation on the wiki, and it now corresponds to the latest version, 1.2.2 (I made a little bugfix, which is why it is 1.2.2 now).

Community
  • 1
  • 1
Vivin Paliath
  • 94,126
  • 40
  • 223
  • 295
13

I have used this jQuery formValidator several times in conjunction with a whole bunch of different environments. I hope it helps as I've rarely spent more than an hour setting it up.

Cheers!

Mitch Malone
  • 882
  • 6
  • 17
8

I would say the jQuery Validation plugin does a good job. I have it combined with the metadata plugin to pass the server-side validation parameters to the client. I've also wrapped a few key points to all forms so that I can use a common pattern for validation, and a few exceptional/custom states. This includes a custom alert message and display.

It does not do everything you want out of the box, but it is the best option and the best default behavior I've seen. Again, I do use the metadata (attribute "data-meta") with it. And it can be bent to your will. I'm also using metadata for control binding to input elements client-side. This splits my client-side logic from server-side, but easier in the long run over trying to inject js from the server-side logic.

200_success
  • 7,286
  • 1
  • 43
  • 74
Tracker1
  • 19,103
  • 12
  • 80
  • 106
5

Parsley.js looks to be a nice and popular choice at time of writing (august 2013).

Simone
  • 20,302
  • 14
  • 79
  • 103
2

Answering this myself since someone on our team noticed Validator from jQuery Tools !

  • Presentation - Supports HTML5 input fields. pattern fields make sure the user can only input test in a certain pattern.
  • Side effects - Triggers events on the form and on individual fields: onFail and onSuccess
  • Widget-driven elements - "Custom input types" are encouraged. The basic demo even includes a natural numbers-old "age" field.
  • Groups - Write a "function matcher" whose sole purpose is to filter which fields are to be validated.
  • Server-side validation - Does it and does it intelligently — depends on your validator calling a callback (so it's async-friendly) instead of a return value.
  • Multiple forms per page - jQuery Tools seems to be very well built and this shouldn't be a problem.
  • Customizable error display - Errors next to fields? All in one place? No problem. Still not good enough? Bind events on failure. Even uses tooltips by default.
  • Snappiness - Demos are very snappy
  • Submit buttons - No problem.

Update: Yep, just reimplemented a chunk of our site with jQuery Tools' validator tooltips. Fantastic!

a paid nerd
  • 30,702
  • 30
  • 134
  • 179
  • 7
    It's too bad this was accepted as the answer. jQuery Tools is a total mess, in need of a complete overhaul, in my opinion. The developer, by his own admission, has lost interest in maintaining the project and for more than 6 months has been unsuccessful in finding a programmer willing to take over the project. Stay away from this answer, is my advice, and use the [very excellent plugin developed by a member of the jQuery team](http://bassistance.de/jquery-plugins/jquery-plugin-validation/). – Sparky Mar 15 '12 at 21:01
  • I accepted this answer because jQuery Tools, despite being a little neglected, is still the best because it's HTML5 aware, compatible with IE7 and IE9, and is easily reusable (we have site-wide defaults for behavior and validators). The bassistance.de Validator plugin has been a source of pain for the three years and we've done everything we can to remove it. – a paid nerd Mar 15 '12 at 22:17
  • I couldn't disagree more but that's not something for discussion in these comments. – Sparky Mar 15 '12 at 22:27
  • I haven't tried jQuery tools validation, but the bassistance validator has been frustrating for me, too. – Ronnie Overby Sep 27 '12 at 15:10
  • @Sparky672 1.5 years later, we're still happy with this choice. jQuery Tools remains the most flexible. – a paid nerd Sep 27 '12 at 21:01
  • 2
    This library looks like it's lacking support – deefour Jan 20 '13 at 03:08
  • That link is now broken and this library sucks. Randomly some code I'm maintaining has stopped producing the side effect when `validate()` returns false. The useless obfuscation is making it a real pain to find where that functionality actually exists. – evanmcdonnal Sep 09 '15 at 16:35
1

Server-side validation rocks.

Supply the results of such validation via an AJAX request if you like... or use a server-side framework that will also add client-side validation - but don't write it twice.

Fenton
  • 241,084
  • 71
  • 387
  • 401
  • 4
    why not validate both client and server for further security? or is that a redundant? i guess the question is why 'don't write it twice' – KJYe.Name Jan 28 '11 at 13:33
  • 5
    I believe I suggested both server and client side validation - but using a server-side framework that will generate the client-validation. Why? Because you shouldn't find yourself in a scenario where you have to change the "server" validation for postcode, and then the "client" validation for postcode. Having one rule in one place makes your code maintainable. – Fenton Jan 28 '11 at 13:49
  • I'm working on a Spring integration to Regula. I haven't posted about it though, but I've worked out a way to translate Hibernate Validation Constraints to Regula constraints on the client-side. This way, you *mostly* have to perform validation once. – Vivin Paliath Jan 29 '11 at 16:59
  • The problem with using server side validation only is that when it is going to be used as often as the original question indicates you are basically using an http connection per every validation event. So yes, you might be adhering to DRY if you do this, but you'll need to weigh that against the overhead of having way more connections hit your servers/network than necessary as opposed to one at the end of each form submission. – whaley Jan 30 '11 at 13:45
  • @whaley - don't forget that lots of frameworks turn your server-side validation into client-side validation automatically. The idea is, write it once and let the framework do an entirely client-side validation for you. For example, ASP.NET MVC uses attributes on the model to do both server-side and client-side validation, so you just maintain one attribute rather than repeating validation in many languages / places. – Fenton Jan 31 '11 at 12:58
  • @kjy112: using GWT you can share server/client Java code. If you use JavaScript, check out http://stackoverflow.com/q/8274413/309483 – Janus Troelsen Feb 04 '13 at 12:16
0

Go with jQuery Validation plugins. It never failed me so far

Hello Universe
  • 3,248
  • 7
  • 50
  • 86
0
 function isEmpty(text) {
if(text == undefined) {
    return true;
}
if(text.replace(/\s+/g, ' ').length == 0) {
    return true;
}
return false;
}

function isValidBoolean(text) {
   if(text == undefined || (text.toLowerCase() != "true" &&    text.toLowerCase() != "false")) {
    return false;
}
return true;
 }

  function isValidDouble(text) {
     var out = parseFloat(text);
   if(isNaN(out)) {
    return false;
  }
  return true;
  }

  function isValidLong(text) {
var out = parseInt(text);
if(isNaN(out)) {
    return false;
}
return true;
}

 function isValidDate(text) {
if(Date.parseString(text, 'MM/dd/yyyy HH:mm:ss') == null) {
    return false;
}
return true;
}

  function hasDuplicates(array) {
var valuesSoFar = {};
for (var i = 0; i < array.length; ++i) {
    var value = array[i];
    if (Object.prototype.hasOwnProperty.call(valuesSoFar, value)) {
        return true;
    }
    valuesSoFar[value] = true;
}
return false;
}
Robert
  • 5,278
  • 43
  • 65
  • 115