vette
v3.7.0
Published
validation
Downloads
10
Readme
Vette 3.x
NOTE Version 1.x was built with RequireJS. This is no longer the case. Vette 2.x+ will only support CommonJS loaders like Browserify.
Prerequisites
- Node.js + npm
Installation
- Run
npm install
in the project root to fetch dependencies. - Reference the Vette module in your own scripts.
- Compile with a CommonJS module loader like Browserify. All dependencies should be included.
Use
Given the following example form...
<form id="create-user">
<h1>Create User</h1>
<fieldset>
<div>
<label>email</label>
<input name="email" type="text" />
<p class="error-message"><!-- hidden --></p>
</div>
<div>
<label>password</label>
<input name="password" type="password" />
<input name="verify-password" type="password" />
<p class="error-message"><!-- hidden --></p>
</div>
<div>
<button>login</button>
</div>
</fieldset>
</form>
Add validation rules to an instance of Vette.
'use strict';
var Vette = require('vette');
var ruleset = new Vette('jquery');
ruleset.add('[name=email]', Vette.required());
ruleset.add('[name=password]', Vette.minLength(10));
ruleset.add('[name=password]', Vette.same('[name=verify-password']));
// or
// ruleset.add('[name=password]',
// Vette.minLength(10),
// Vette.same('[name=verify-password']));
Invoke validation when the user performs an action, like submitting a form.
var $form = $('form#create-user');
$form.on('submit', function (e) {
e.preventDefault();
/*
* `evaluate()` returns a promise that will be fulfilled if all
* validation rules pass.
*/
var evaluation = ruleset.evaluate($form);
evaluation.done(function () {
// submit the form via ajax or something
});
evaluation.fail(function (allViolations) {
// show all violations in a big message
});
});
Set up handlers for Vette events.
evaluating
: occurs before validation beginsevaluated
: occurs after validation finishesvalidation-failed
: occurs when a specific rule generates a violation
ruleset.on('validation-failed', function (selector, violations) {
/*
* Occurs when validation fails for a given field (selector).
* All violations will be in the `violations` array. If you
* want to display the *first* violation that occurred, just
* grab the first element of the array. Note that all violations
* are instances of Error or a subtype of Error.
*/
var firstViolation = violations[0];
$form.find(selector)
.addClass('invalid')
.siblings('.error-message')
.text(firstViolation.message)
.show();
});
ruleset.on('evaluating', function () {
/*
* Occurs before fields are validated. Useful
* for resetting form state, hiding previous error
* messages, etc.
*/
$form.find('.invalid').removeClass('invalid');
$form.find('.error-message').hide();
});
ruleset.on('evaluated', function () {
/*
* Validation is complete.
*/
});
Profit!
Available validator rules
Generic rules
required
: a value is required (same asminLength(1)
)match(regex)
: a value matches a particular regular expressionminLength(length)
: a string value must be a certain lengthmaxLength(length)
: a string value cannot be greater than a certain lengthany(options)
: a value may be any value in an array of options (but must be one)same(selector)
: a value has the same value as anotherdifferent(selector)
: a value is different than another
Numeric rules
numeric()
: a value must be numericrange(lower, upper, inclusive)
: a value must be within a given numeric range (not inclusive by default)gt(number)
: a value must be greater than a given numberlt(number)
: a value must be less than a given numbergteq(number)
: a value must be greater to, or equal than, a given numberlteq(number)
: a value must be less than, or equal to, a given number
Collection rules
nodupe()
: no duplicate values may be present in an array valuehasAll()
: every element in the collection passes a specified predicatehasAny()
: any element in a collection passes a specified predicatehasNone()
: no elements in a collection pass a specified predicatehasOne()
: one, and only one, element in a collection passes a specified predicate
Date rules
before(selector, inclusive)
: a date value must occur before another date value (not inclusive by default)after(selector, inclusive)
: a date value must occur after another date value (not inclusive by default)
Advanced rules
Create a custom "accessor" to fetch values, provide intelligent defaults, etc.
function defaultLevelValue($e) {
// generate the value for [name=level]
var value = $e.val();
return !value ? 'none' : value;
}
ruleset.add('[name=level]', Vette.accessor(
defaultLevelValue,
Vette.any(['none', 'novice', 'journeyman', 'master'])
));
Determine if a rule should even be evaluated by using a precondition. Preconditions may be truthy values or functions that return truthy values.
// using a primitive
var isNotEmpty = true;
ruleset.add('[name=middleName]', Vette.precondition(
isNotEmpty,
Vette.minLength(2) //only executes if isNotEmpty() returns true
));
// using a function
function isNotEmpty(value) {
return !!value;
}
ruleset.add('[name=middleName]', Vette.precondition(
isNotEmpty,
Vette.minLength(2) //only executes if isNotEmpty() returns true
));
Compose several rules that can be reused together.
var composed = Vette.compose(
Vette.numeric(),
Vette.gteq(10),
Vette.lt(100)
);
ruleset.add('[name=team1-score]', composed);
ruleset.add('[name=team2-score]', composed);
A word about adapters
Vette was originally coupled tightly to jQuery, but as it is useful in other contexts (besides just validating HTML form fields) it became obvious that the code would need to change a bit. When a Vette instance is created, an optional adapter name may be passed to the constructor.
var ruleset = new Vette('jquery');
Adapters wrap object passed to vette.evaluate()
and are used to find other nested objects or values within the evaluated object.
Consider an HTML <form>
element. It may have many <input>
elements as children, and each of these <input>
elements has some value. So an adapter wraps the <form>
element, can find other child elements by selector, and retrieve the values from those child elements.
Or consider a plain JavaScript object. It has named properties which themselves may be objects. An adapter can navigate the object tree, find properties, and return their values.
The hashAdapter
shows the simple interface all adapters must possess. It encapsulates a single object and may look up properties on that object, or return values from those properties.
function hashAdapter (object) {
return {
find: function (property) {
return hashAdapter(object[property]);
},
value: function () {
return object;
}
}
}
Internally, Vette uses the hash adapter to navigate the properties of an object.
var foo = {
bar: {
baz: 'ding ding ding!'
}
};
// Vette internals
var rootAdapter = hashAdapter(foo);
var barAdapter = hashAdapter.find('bar'); // {baz: 'ding ding ding!'}
var bazAdapter = barAdapter.find('baz'); // 'ding ding ding!'
var oopsAdapter = bazAdapter.find('doesNotExist'); // undefined
Pre-defined adapters
There are three pre-defined adapters in Vette.
hash
- fetches properties and values from an object literal (default adapter)dom
- fetches elements and values in an HTML page usingElement.querySelector()
andElement.value
syntaxjquery
- fetches elements and values in an HTML page using$Element.find()
and$Element.val()
syntax.
When a Vette instance is create it defaults to using the hash
adapter. If another adapter name is passed to the constructor function, the instance will use that adapter instead. Objects passed to vette.evaluate()
will be wrapped with the configured adapter.
Custom adapters
A custom adapter:
- is a function that accepts a single argument--the object passed to
vette.evaluate()
--and returns - an object with two methods:
find(identifier)
- returns some value wrapped in the same kind of adapter, andvalue()
- returns the actual value passed to the adapter function
(The src/adapters/*.js
files are good reference implementations.)
To add a custom adapter to Vette, assign it as a property to Vette's adapters hash before creating a Vette instance:
Vette.adapters.myAdapter = function (myObject) {
// ...
};
var myObject = {/*...*/};
var ruleset = new Vette('myAdapter');
ruleset.add(/*...*/);
ruleset.evaluate(myObject);
TODO:
- demos
- enhance
hashAdapter
with l33teral