Validate.js 表单验证插件
Validate.js provides a declarative way of validating javascript objects.
It is unit tested with 100% code coverage and can be considered fitfor production.
The project can be found on GitHub where you can also find our issue tracker.
There is also a Travis project used for testing, a Coveralls project used to code coverage as well as the annotated source.
Validate.js is an open source component of Wrapp and is licensed under the MIT license.
Downloads
38KB, uncompressed and plenty of comments
5.05KB, minified and gzipped
(Source map)
Might not be 100% stable
Installing
Browser/CDN
<codeclass="lang-markup"><script src="//cdnjs.cloudflare.com/ajax/libs/validate.js/0.13.1/validate.min.js"></script>
Require.js/AMD
<codeclass="lang-js">require(["validate.js"], function(validate) { // ... });
npm/node.js
<codeclass="lang-bush">$ npm install --save validate.js
<codeclass="lang-js">var validate = require("validate.js");
Bower
<codeclass="lang-bush">$ bower install --save validate.js
Component
<codeclass="lang-bush">$ component install ansman/validate.js
Dependencies
There are no required external dependencies at all! Though for the
datetime and date validator to you need to specify a parse and format
function and for that you most likely will want to use a library,
moment.js is highly recommended.
If you want to use async validation you need to use a runtime that
supports Promises.
You can tell validate.js to use any A+ compatible promise implemention
like this:
<codeclass="lang-js">// Simply set validate.Promise to be the promise constructor // RSVP works validate.Promise = RSVP.Promise; // and Q.js too validate.Promise = Q.Promise;
Overview
There are already many validation libraries out there today but most of them
are very tightly coupled to a language or framework.
The goal of validate.js is to provide a cross framework and cross language
way of validating data. The validation constraints can be declared in JSON
and shared between clients and the server.
Important!
One thing that is a bit unorthodox is that most validators will
consider undefined values (null
and undefined
,) valid values. So for example adding a constraint of
at least 6 characters will be like saying If the attribute is given
it must be at least 6 characters.
This differs from example Ruby on Rails where validators instead have
the allow_nil
option. I find it quite common that you
want to have constraints on an optional attribute.
One core value of this library is that nothing should be private or
inaccessable. If you want to modify which values are considered
empty for example you can simply overwritevalidate.isEmpty
, this way you don't have to wait for
a pull request to be accepted or create a fork.
Supported runtimes
Validate.js works with any ECMAScript 5.1 runtime which means it works in
both the browser and in node.js
All modern browsers are supported (IE9+, Firefox 3+, Opera 10.5+, Safari 4+, Chrome).
Examples
You can find some basic examples included in the project.
They are meant to give a feeling for how to use the library and
should not be considered production ready code.
The native HTML form validate has been disabled in a demo purpose
so that you may see how validate.js works in action.
Acknowledgements
- The design of these docs pages have been heavily inspired by backbonejs.org.
- All the validators have been inspired by Rails' validators.
Constraints
The constraints have the following format
{
<attribute>: {
<validator name>: <validator options>
}
}
Unless otherwise specified you can always specify the message
option to customize the message returned if the validator doesn't pass.
Just remember to not include the attribute name since it's automatically
prepended to the error message.
The message can also be a function which will be called to retrieve
the message, besides this it is treated like a normal message (the
attribute name is prepended etc).
If the message is not a function and not a string it is simply
returned as is.
Sometimes it's nice to be able validate field differently depending
on the input itself.
validate.js allows the validators object and validator options to be
a function that should return the constraints/options:
<codeclass="lang-js">var constraints = { creditCardNumber: { presence: true, format: { pattern: /^(34|37|4|5[1-5]).*$/, message: function(value, attribute, validatorOptions, attributes, globalOptions) { return validate.format("^%{num} is not a valid credit card number", { num: value }); } }, length: function(value, attributes, attributeName, options, constraints) { if (value) { // Amex if ((/^(34|37).*$/).test(value)) return {is: 15}; // Visa, Mastercard if ((/^(4|5[1-5]).*$/).test(value)) return {is: 16}; } // Unknown card, don't validate length return false; } }, creditCardZip: function(value, attributes, attributeName, options, constraints) { if (!(/^(34|37).*$/).test(attributes.creditCardNumber)) return null; return { presence: {message: "is required when using AMEX"}, length: {is: 5} }; } }; validate({creditCardNumber: "4"}, constraints); // => {"creditCardNumber": ["Credit card number is the wrong length (should be 16 characters)"]} validate({creditCardNumber: "9999999999999999"}, constraints); // => {"creditCardNumber": ["9999999999999999 is not a valid credit card number"]} validate({creditCardNumber: "4242424242424242"}, constraints); // => undefined validate({creditCardNumber: "340000000000000"}, constraints); // => {"creditCardZip": ["Credit card zip is required when using AMEX"]}
If you don't want to give any options to a validator you may passtrue
instead of an empty object. The validator will not
be run if the options are falsy.
Important! Most validators consider undefined values
(null
and undefined
) valid values so make
sure you use the presence
validator on attributes that
are required.
Validate function
validatevalidate(attributes, constraints, [options])
Validates the attributes object against the constraints.
The attributes must be a plain object or a form element,
things like backbone models etc are not supported.
For the format of the constraints see the constraints section.
If the attributes objects is an HTML/DOM/jQuery elementcollectFormValues
is called before validating.
If there are no errors nothing is returned. Otherwise an object in this
format is returned: {<attribute>: [<error>, <error>, ...]}
Since validators don't include the argument name in the error message
the validate function prepends it for them. This behaviour can be
disabled by setting the fullMessages option to false
.
If you need an error not to be prefixed by the attribute add a leading^
to the error and it won't be prepended. If you need to
have a leading ^
but want the prefixing just write \^
.
If you include %{value}
in the error message it will be
replaced with the actual value. The value is transformed usingvalidate.stringifyValue
(which per default just callsvalidate.prettify
) but it can be overidden to customize
the formatting.
If you want to customize how the attribute names are prettified you
can either override the validate.prettify
function
or you can give a function as the prettify option.
There is also a format option. To see more details about this
option see
the section about it.
<codeclass="lang-js">var constraints = { username: { presence: true, exclusion: { within: ["nicklas"], message: "'%{value}' is not allowed" } }, password: { presence: true, length: { minimum: 6, message: "must be at least 6 characters" } } }; validate({password: "bad"}, constraints); // => { // "username": ["Username can't be blank"], // "password": ["Password must be at least 6 characters"] // } validate({username: "nick", password: "better"}, constraints); // => undefined validate({username: "nicklas", password: "better"}, constraints); // => {"username": ["Username 'nicklas' is not allowed"]} validate({password: "better"}, constraints, {fullMessages: false}); // => {"username": ["can't be blank"]} validate({}, constraints, {format: "flat"}); // => ["Username can't be blank", "Password can't be blank"] validate({username: "nicklas", password: "bad"}, constraints, {format: "detailed"}); // => [ // { // "attribute": "username", // "value": "nicklas", // "validator": "exclusion", // "globalOptions": { // "format": "detailed" // }, // "attributes": { // "username": "nicklas", // "password": "bad" // }, // "options": { // "within": [ // "nicklas" // ], // "message": "'%{value}' is not allowed" // }, // "error": "Username 'nicklas' is not allowed" // }, // { // "attribute": "password", // "value": "bad", // "validator": "length", // "globalOptions": { // "format": "detailed" // }, // "attributes": { // "username": "nicklas", // "password": "bad" // }, // "options": { // "minimum": 6, // "message": "must be at least 6 characters" // }, // "error": "Password must be at least 6 characters" // } // ] validate({}, {username: {presence: {message: "^You must pick a username"}}}); // => {"username": ["You must pick a username"]}
Async validation
validate.asyncvalidate.async(attributes, constraints, [options])
Even though none of the built in validators are async it is sometimes
useful to have async validations. One example would be to check if
a username is already used by asking the server.
Validate.js supports async validations through the validate.async
function. It has the same signature as the regular validation function.
validate.async
returns a
Promise
that is resolved if the validation passes and is rejected if the
validation failed, passing the errors as the first argument.
The errors has the same format as the errors from the regular validation function.
Besides accepting all options as the non async validation function
it also accepts two additional options; cleanAttributes which,
unless false
, makes validate.async
call validate.cleanAttributes
before resolving the promise and wrapErrors which can be
a function or constructor that will be called with the errors,
options, attributes and constraints if an error occurs. This allows
you to define a better way of catching validation errors.
If an Error
is thrown from an async validator the
argument passed to the rejection handler will be that error. This
allows you to differentiate from coding errors and validation errors.
You can use the async validate function even if no validations
are async, it still returns a promise. You can not, however, use
the regular function with async validations.
Any A+ type promise can be used, just override validate.Promise
with the constructor of the new Promise implementation.
Validate.js will try to use the global Promise function if it exists
otherwise it will throw an exception when using validate.async
Please note that jQuery's promise implementation is not A+
compatible and will not work.
Example:
<codeclass="lang-js">function success(attributes) { console.log("Success!", attributes); } function error(errors) { if (errors instanceof Error) { // This means an exception was thrown from a validator console.err("An error ocurred", errors); } else { console.log("Validation errors", errors); } } var constraints = { name: { presence: true }, // This is so the country doesn't get removed when cleaning the attributes country: {} }; var attributes = { name: "Nicklas", country: "Sweden", someMaliciousAttribute: "scary value" }; // Will call the success function and log { // name: "Nicklas", // country: "Sweden" // } validate.async(attributes, constraints).then(success, error); // Will call the error function validate.async({}, constraints).then(success, error); function ValidationErrors(errors, options, attributes, constraints) { Error.captureStackTrace(this, this.constructor); this.errors = errors; this.options = options; this.attributes = attributes; this.constraints = constraints; } ValidationErrors.prototype = new Error(); // This isn't supported by the ES6 promises validate.async({}, constraints, {wrapErrors: ValidationErrors}) .then(success) .catch(ValidationErrors, function(error) { // Handle the validation errors console.log("ValidationErrors", error); }) .catch(function(error) { // Handle other errors; console.log("SystemError", error); }); // Supporting another promise implementation (RSVP in this case) validate.Promise = RSVP.Promise;
Single value validation
validate.singlevalidate.single(value, constraints, [options])
Sometimes you only want to validate a single value against some
constraints and using the normal validate function is quite
verbose so there is a shorthand for this.
It does little more than proxying the call to the main validation
function but with the value wrapped in an object and the options
fullMessages and format set to "flat"
.
This is because there is no name which means it can't produce
full messages.
You can use the provided format,
capitalize and
prettify
utility functions to append your own name.
<codeclass="lang-js">validate.single(null, {presence: true, email: true}); // => ["can't be blank"] validate.single("foo", {presence: true, email: true}); // => ["is not a valid email"] validate.single("[email protected]", {presence: true, email: true}); // => undefined
Nested validation
Validate.js also has limited support for nested objects (objects
within objects) using the dot notation.
The implementation is fairly basic and doesn't do anything clever
with the messages. It doesn't support things like only validating a
sub key if the parent key is present so for more advanced validations
multiple validation schemas are recommended.
<codeclass="lang-js">var constraints = { "addresses.shipping": { presence: true }, "addresses.shipping.street": { format: { // Must be numbers followed by a name pattern: "^[0-9]+ .+$", message: "^The street for the shipping address must be a valid street name" } } }; validate({}, constraints); // => {"addresses.shipping": ["Addresses shipping can't be blank"]} validate({addresses: {shipping: {street: "Foobar"}}}, constraints); // => {"addresses.shipping.street": ["The street for the shipping address must be a valid street name"]} validate({"foo.bar": 3}, {"foo\\.bar": {numericality: {even: true}}}); // => {"foo\.bar": ["Foo bar must be even"]}
Default options
Both the validate
, validate.async
as well
as all validators support specifying default options by setting
the options
property on the respective function or
validator.
Most validators allow you to specify default messages in addition
to default options, refer to the documentation for the individual
validators for information on how to do this.
<codeclass="lang-js">var constraints = { name: { presence: true } }; validate.options = {format: "flat"}; validate.async.options = {format: "flat", cleanAttributes: false}; validate.validators.presence.options = {message: "can't be empty"}; // The default options will be used for both the // validator and the validate function validate({}, constraints); // => ["Name can't be empty"] // The default options are not used if the constraints options are falsy validate({format: "grouped"}, {}); // => undefined
Error formatting
validate.js allows the result from the validate function to be
formatted in different ways.
"grouped"
(default) - Returns error messages grouped by attribute."flat"
- Returns a flat list of error messages."detailed"
- Returns a list of error objects containing more info on the error (see example). Each object will only contain a single message.
You can also create custom formatters by adding them to thevalidate.formatters
object. The formatter should be
a function that accepts a list of errors that have the same format
as the detailed format.
<codeclass="lang-js">var constraints = { username: { presence: true, exclusion: { within: ["nicklas"], message: "'%{value}' is not allowed" } }, password: { presence: true, length: { minimum: 6, message: "must be at least 6 characters" } } }; validate({}, constraints, {format: "flat"}); // => ["Username can't be blank", "Password can't be blank"] validate({username: "nicklas", password: "bad"}, constraints, {format: "detailed"}); // => [ // { // "attribute": "username", // "value": "nicklas", // "validator": "exclusion", // "globalOptions": { // "format": "detailed" // }, // "attributes": { // "username": "nicklas", // "password": "bad" // }, // "options": { // "within": [ // "nicklas" // ], // "message": "'%{value}' is not allowed" // }, // "error": "Username 'nicklas' is not allowed" // }, // { // "attribute": "password", // "value": "bad", // "validator": "length", // "globalOptions": { // "format": "detailed" // }, // "attributes": { // "username": "nicklas", // "password": "bad" // }, // "options": { // "minimum": 6, // "message": "must be at least 6 characters" // }, // "error": "Password must be at least 6 characters" // } // ] validate.formatters.custom = function(errors) { return errors.map(function(error) { return error.validator; }); }; validate({username: "nicklas", password: "bad"}, constraints, {format: "custom"}); // => ["exclusion", "length"];
Writing your own validator
Writing your own validator is super simple! Just add it to thevalidate.validators
object and it will be automatically
picked up.
The validator receives the following arguments:
- value - The value exactly how it looks in the attribute object.
- options - The options for the validator. Guaranteed to not
benull
orundefined
. - key - The attribute name.
- attributes - The entire attributes object.
- globalOptions - The options passed when calling
validate
(will always be an object, non null).
If the validator passes simply return null
or undefined
.
Otherwise return a string or an array of strings containing the
error message(s).
Make sure not to prepend the key name, this will be done automatically.
<codeclass="lang-js">validate.validators.custom = function(value, options, key, attributes) { console.log(value); console.log(options); console.log(key); console.log(attributes); return "is totally wrong"; }; // Will log: // - "some value" // - "some options" // - "foo" // - {"foo": "some value"} validate({foo: "some value"}, {foo: {custom: "some options"}}); // => {foo: ["Foo is totally wrong"]}
Writing an async validator
Async validators are equal to a regular one in every way except
in what they return. An async validator should return a promise
(usually a validate.Promise
instance).
The promise should be resolved with the error (if any) as its only
argument when it's complete.
If the validation could not be completed or if an error occurs
you can call the reject handler with an Error
which will make the whole validation fail and be rejected.
<codeclass="lang-js">validate.validators.myAsyncValidator = function(value) { return new validate.Promise(function(resolve, reject) { setTimeout(function() { if (value === "foo") resolve(); else resolve("is not foo"); }, 100); }); }; var constraints = {name: {myAsyncValidator: true}} , success = alert.bind(this, "The validations passed") , error = function(errors) { alert(JSON.stringify(errors, null, 2)); }; // Will call the success callback validate.async({name: "foo"}, constraints).then(success, error); // Will call the error callback with {name: ["Name is not foo"]} as the first argument validate.async({name: "bar"}, constraints).then(success, error);
Validators
date
The date validator is just a shorthand for the
datetime validator
with the dateOnly
option set to true
.
datetime
This datetime validator can be used to validate dates and times.
Since date parsing in javascript is very poor some additional work
is required to make this work.
Before this validator can be used the parse and format functions
needs to be set. The parse function should take the value to parse
(non null but otherwise untouched) and return the unix timestamp
(in milliseconds) for that date or NaN
if it's invalid.
It's important to mention that the constraints (earliest, latest)
will also be parsed using this method.
The format function should take a unix timestamp (in milliseconds)
and format it in a user friendly way.
You can specify the follow constraints:
- earliest
- The date cannot be before this time. This argument will be parsed
using theparse
function, just like the value.
The default error must be no earlier than %{date} - latest
- The date cannot be after this time. This argument will be parsed
using theparse
function, just like the value.
The default error must be no later than %{date} - dateOnly
- If true, only dates (not datetimes) will be allowed.
The default error is must be a valid date
You can change the messages by setting any of these settings
on the validate.validators.datetime
object or on the
options for the validator:
notValid
tooEarly
tooLate
You can use the placeholders %{value}
and%{date}
in the messages.
<codeclass="lang-js">// Before using it we must add the parse and format functions // Here is a sample implementation using moment.js validate.extend(validate.validators.datetime, { // The value is guaranteed not to be null or undefined but otherwise it // could be anything. parse: function(value, options) { return +moment.utc(value); }, // Input is a unix timestamp format: function(value, options) { var format = options.dateOnly ? "YYYY-MM-DD" : "YYYY-MM-DD hh:mm:ss"; return moment.utc(value).format(format); } }); validate({}, {departure: {datetime: true}}); // => undefined validate({departure: "foobar"}, {departure: {datetime: true}}); // => {"departure": ["Departure must be a valid date"]} validate({departure: "2013-12-11 10:09:08"}, {departure: {datetime: true}}); // => undefined validate({departure: "2013-12-11 10:09:08"}, {departure: {datetime: {dateOnly: true}}}); // => {"departure": ["Departure must be valid date"]} var constraints = { birthday: { datetime: { dateOnly: true, latest: moment.utc().subtract(18, 'years'), message: "^You need to be at least 18 years old" } } }; validate({birthday: "3013-11-14"}, constraints); // => {"birthday": ["You need to be at least 18 years old"]}
The email validator attempts to make sure the input is a valid email.
Validating emails is tricky business due to the complex rules of
email address formatting.
For example [email protected]
is a perfectly valid email
but it's most likely just the case that John has forgotten to write.com
at the end.
Validate.js tries to be pragmatic and allows most valid emails but
tries to catch common typos such as forgetting the TLD.
If you want to know more about email validation the
Wikipedia article
and the email page on regular-expressions.info
are good places to start.
You can customize the regexp used by setting validate.validators.email.PATTERN
to a regexp of your chosing, just remember that javascript regexp
does substring matching.
The default message is is not a valid email and as usual you
can override it using the message option or by settingvalidate.validators.email.message
<codeclass="lang-js">var constraints = { from: { email: true } }; validate({from: null}, constraints); // => undefined validate({from: ""}, constraints); // => {"email": ["From is not a valid email"]} validate({from: "[email protected]"}, constraints); // => {"email": ["From is not a valid email"]} // Any TLD is allowed validate({from: "[email protected]"}, constraints); // => undefined // Upper cased emails are allowed validate({from: "[email protected]"}, constraints); // => undefined constraints = { from: { email: { message: "doesn't look like a valid email" } } }; validate({from: "foobar"}, constraints); // => {"email": ["From doesn't look like a valid email"]} // It allows unicode validate({from: "first.lä[email protected]"}, constraints); // => undefined
equality
The equality validator can be used to verify that one attribute
is always equal to another.
This is useful when having a "confirm password" input for
example.
You specify which attribute by simply using the name of it
as the options for the validator or by giving the option
attribute.
By default ===
is used to check the quality, it you
need to validate more complex objects you can give a function
using the comparator option which should be a function
that accepts two arguments and returns true
if they
objects are equal and false
if they are not.
The default message is is not equal to %{attribute}validate.validators.equality.message
<codeclass="lang-js">var constraints = { confirmPassword: { equality: "password" } }; validate({password: "foo", confirmPassword: "foo"}, constraints); // => undefined validate({password: "foo", confirmPassword: "bar"}, constraints); // => {confirmPassword: ["Confirm password is not equal to password"]} constraints = { complexAttribute: { equality: { attribute: "otherComplexAttribute", message: "is not complex enough", comparator: function(v1, v2) { return JSON.stringify(v1) === JSON.stringify(v2); } } } }; validate({complexAttribute: [1,2,3], otherComplexAttribute: [1,2,3]}, constraints); // => undefined validate({complexAttribute: [1,2,3], otherComplexAttribute: [3,2,1]}, constraints); // => {complexAttribute: ["Complex attribute is not complex enough"]}
exclusion
The exclusion validator is useful for restriction certain values.
It checks that the given value is not in the list given by the
within option.
You can specify within as a list or as an object (in which
case the keys of the object are used).
The default message is ^%{value} is restricted
and can be changed by settingvalidate.validators.exclusion.message
<codeclass="lang-js">var restrictedDomains = ["jp", "ch"]; validate({}, {subdomain: {exclusion: restrictedDomains}}); // => undefined validate({subdomain: "jp"}, {subdomain: {exclusion: restrictedDomains}}); // => {"size": ["jp is restricted"]} var constraints = { subdomain: { exclusion: { within: {jp: "Japan", "ch": "China"}, message: "^We don't support %{value} right now, sorry" } } }; validate({subdomain: "jp"}, constraints); // => {"subdomain": ["We don't support Japan right now, sorry"]} validate({subdomain: "com"}, constraints); // => undefined
format
The format validator will validate a value against a regular expression
of your chosing.
The default message if the value doesn't match is is invalid
so you'll likely want to customize it by settings message
to something in the options or by setting a new global default
message using validate.validators.format.message
The pattern option can either be a javascript regexp or
string that will be passed to the
RegExp
constructor. If the pattern is a string and you want to specify flags
you may use the flags option.
Please note that the whole string must match the regexp, not just a
part of the value.
<codeclass="lang-js">var pattern = /\d{5}(-\d{4})?/; validate({}, {zipCode: {format: pattern}}); // => undefined validate({zipCode: "foobar"}, {zipCode: {format: pattern}}); // => {"zipCode": ["Zip code is invalid"]}; validate({zipCode: "12345"}, {zipCode: {format: pattern}}); // => undefined var constraints = { username: { format: { pattern: "[a-z0-9]+", flags: "i", message: "can only contain a-z and 0-9" } } }; validate({username: "Nicklas!"}, constraints); // => {"username": ["Username can only contain a-z and 0-9"]} validate({username: "Nicklas"}, constraints); // => undefined
inclusion
The inclusion validator is useful for validating input from a dropdown
for example.
It checks that the given value exists in the list given by the within option.
You can specify within as a list or as an object (in which
case the keys of the object are used).
The default message is ^%{value} is not included in the list
and can be changed by settingvalidate.validators.inclusion.message
<codeclass="lang-js">var sizes = ["small", "medium", "large"]; validate({}, {size: {inclusion: sizes}}); // => undefined validate({size: "xlarge"}, {size: {inclusion: sizes}}); // => {"size": ["xlarge is not included in the list"]} var constraints = { size: { inclusion: { within: {"Small": "s", "Medium": "m", "Large": "l"}, message: "^We're currently out of %{value}" } } }; validate({size: "Extra large"}, constraints); // => {"size": ["We're currently out of Extra large"]} validate({size: "Medium"}, constraints); // => undefined
length
The length validator will check the length of a string.
Any object with the length
property can be validated
but all the default error messages refers to strings so make sure
you override them if you plan on validating arrays using this.
You may specify the following length constraints:
- is
- The value has to have exactly this length. The default error is
is the wrong length (should be %{count} characters) - minimum
- The value cannot be shorter than this value. The default error is
is too short (minimum is %{count} characters) - maximum
- The value cannot be longer than this value. The default error is
is too long (maximum is %{count} characters)
You can specify the error message using the notValid,
wrongLength, tooShort and tooLong options.
The default values are
has an incorrect length,
is the wrong length (should be %{count} characters),
is too short (minimum is %{count} characters) and
is too long (maximum is %{count} characters) respectively.
As you may have noticed you can use %{count}
as a placeholder
for the actual constraint and it will be replaced for you.
The default messages can also be changed by setting the following
attributes on validate.validators.length
:
notValid
tooLong
tooShort
wrongLength
You can also use the message as the message for all errors
(this overrides any other custom errors).
Per default the number of characters are counted (using the length
property), if you want to count something else you can specify the
tokenizer option which should be a function that takes a single
argument (the value) and the returns a value that should be used when
counting.
The tokenizer will never be called with nil
or undefined
as an argument.
Once important thing to note is that the value needs to have a numeric
value for the length
property or the message has an incorrect length
is returned.
An error is also logged to the console since this is considered a
coding error.
<codeclass="lang-js">var constraints = { key1: {length: {is: 3}}, key2: {length: {minimum: 20}}, key3: {length: {maximum: 3}}, key4: { length: { minimum: 3, tooShort: "needs to have %{count} words or more", tokenizer: function(value) { return value.split(/\s+/g); } } } }; validate({}, constraints); // => undefined // This is because nil and undefined are valid values. // Use the presence validator if you don't want to allow undefined values. var values = { key1: "wrong length", key2: "too short", key3: "too long", key4: "too short" }; validate(values, constraints); // => { // "key1": ["Key1 is the wrong length (should be 3 characters)"], // "key2": ["Key2 is too short (minimum is 20 characters)"], // "key3": ["Key3 is too long (maximum is 3 characters)"], // "key4": ["Key4 needs to have 3 words or more"] // }
numericality
The numericality validator will only allow numbers.
Per default strings are coerced to numbers using the +
operator. If this is not desirable you can set the noStrings
option to true
to disable this behaviour.
The following constraints can be applied:
- onlyInteger
- Real numbers won't be allowed. The error message is must be an integer
- strict
- Enables more strict validation of strings. Leading zeroes won't be allowed and the number cannot be malformed.
- greaterThan
- The input has to be greater than this value. The error message is must be greater than %{count}
- greaterThanOrEqualTo
- The input has to be at least this value. The error message is must be greater than or equal to %{count}
- equalTo
- The input has to be exactly this value. The error message is must be equal to %{count}
- lessThanOrEqualTo
- The input can be this value at the most. The error message is must be less than or equal to %{count}
- lessThan
- The input has to be less than this value. The error message is must be less than %{count}
- divisibleBy
- The input has to be divisible by this value. The error message is must be divisible by %{count}
- odd
- The input has to be odd. The error message is must be odd
- even
- The input has to be even. The error message is must be even
If you want a custom error message you may specify it using the
message option or by settings specifying of the following
messages:
notValid
notInteger
notGreaterThan
notGreaterThanOrEqualTo
notEqualTo
notLessThan
notLessThanOrEqualTo
notDivisibleBy
notOdd
notEven
<codeclass="lang-js">// null and undefined are valid values regardless of the options validate({}, {duration: {numericality: true}}); //= > undefined validate({duration: "foobar"}, {duration: {numericality: true}}); // => {"duration": ["Duration is not a number"]} validate({duration: "3"}, {duration: {numericality: true}}); // => undefined validate({duration: "03"}, {duration: {numericality: true}}); // => undefined validate({duration: "03"}, {duration: {numericality: {strict: true}}}); // => {"duration": ["Duration must be a valid number"]} validate({duration: "3"}, {duration: {numericality: {noStrings: true}}}); // => {"duration": ["Duration is not a number"]} validate({duration: "7"}, {duration: {numericality: {divisibleBy: 3}}}); // => {"duration": ["Duration must be divisible by 3"]} var constraints = { duration: { numericality: { onlyInteger: true, greaterThan: 0, lessThanOrEqualTo: 30, even: true, notEven: "must be evenly divisible by two" } } }; validate({duration: 3.14}, constraints); // => {"duration": ["Duration must be an integer"]} validate({duration: 4711}, constraints); // => { // "duration": [ // "Duration must be less than or equal to 30", // "Duration must be evenly divisible by two" // ] // }
presence
The presence validator validates that the value is defined.
This validator will probably the most used one, it corresponds to
HTML5's required attribute.
You can use the message option to customize the message. The
default message is can't be blank and can be changed by
setting validate.validators.presence.message
.
These are the values that are considered empty:
null
undefined
Additionally you can set the allowEmpty
tofalse
to disallow the following values:
{}
(empty objects)[]
(empty arrays)""
(empty string)" "
(whitespace only string)
Important! All other values are considered valid (including functions)!
<codeclass="lang-js">validate({}, {username: {presence: true}}); // => {"username": ["Username can't be blank"]} validate({username: "ansman"}, {username: {presence: true}}); // => undefined validate({input: ""}, {input: {presence: true}}); // => undefined validate({input: ""}, {input: {presence: {allowEmpty: false}}}); // => {"input:" ["Input can't be blank"]} validate({}, {username: {presence: {message: "is required"}}}); // => {"username": ["Username is required"]} validate.validators.presence.message = "is required"; validate({}, {username: {presence: true}}); // => {"username": ["Username is required"]}
type
The type validator ensures that the input is of the correct type. There are the following build in types.
array
integer
number
string
date
boolean
In addition to these you can also create your own by adding them tovalidate.validator.type.types
.
The following options are supported:
- type - The type to use. Can also be a function for inline type checking. The function will receive the value, options, attribute name, all attributes and the global options respectively.
- message - A custom message. Can also be a function. The function will receive the value, options, attribute name, all attributes and the global options respectively.
<codeclass="lang-js">validate({myAttribute: "value"}, {myAttribute: {type: "string"}}); // => undefined validate({myAttribute: true}, {myAttribute: {type: "string"}}); // => {"myAttribute": ["My attribute must be of type string"]} validate({myAttribute: "other"}, {myAttribute: {type: {type: function(value) { return value === "stuff"; }}}}); // => {"myAttribute": ["My attribute must be of the correct type"]} validate.validators.type.types.customType = function (value) { return value === "stuff"; }; validate({myAttribute: true}, {myAttribute: {type: "customType"}}); // => {"myAttribute": ["My attribute must be of type customType"]} validate.validators.type.messages.customType = "is simply wrong"; validate({myAttribute: true}, {myAttribute: {type: "customType"}}); // => {"myAttribute": ["My attribute is simply wrong"]}
url
The URL validator ensures that the input is a valid URL. Validating
URLs are pretty tricky but this validator follows a gist that can
be found
here.
The following options are supported:
- message - The message if the validator fails. Defaults to
is not a valid url - schemes - A list of schemes to allow. If you want to
support any scheme you can use a regexp here (for example[".+"]
). The default value is["http", "https"]
. - allowLocal - A boolean that if
true
allows
local hostnames such as10.0.1.1
orlocalhost
. The default isfalse
. - allowDataUrl - A boolean that if
true
allows
data URLs as defined in RFC 2397.
The default isfalse
<codeclass="lang-js">validate({website: "http://google.com"}, {website: {url: true}}); // => undefined validate({website: "google.com"}, {website: {url: true}}); // => {"website": ["Website is not a valid url"]} validate({website: "ftp://google.com"}, {website: {url: true}}); // => {"website": ["Website is not a valid url"]} validate({website: "ftp://google.com"}, { website: { url: { schemes: ["ftp"] } } }); // => undefined validate({website: "http://localhost"}, {website: {url: true}}); // => {"website": ["Website is not a valid url"]} validate({website: "http://localhost"}, { website: { url: { allowLocal: true } } }); // => undefined validate({website: "data:,Hello%2C%20World!"}, {website: {url: true}}); // => {"website": ["Website is not a valid url"]} validate({website: "data:,Hello%2C%20World!"}, { website: { url: { allowDataUrl: true } } } ); // => undefined
Utilities
capitalizevalidate.capitalize(string)
Simply makes the first character in the string upper case.
<codeclass="lang-js">validate.capitalize("foobar"); // => "Foobar"
cleanAttributesvalidate.cleanAttributes(attributes, whitelist)
Returns an object that only contains the whitelisted attributes.
It will remove all attributes that have a falsy value in the whitelist.
It also accepts a constraints object used for the validation but
to make it keep attributes that doesn't have any constraints
you can simply set the constraints for that attribute to {}
.
<codeclass="lang-js">var whitelist = { name: true, "address.street": true, "address.postal": true, "something\\.with\\.periods": true }; var attributes = { name: "Nicklas", address: { street: "Drottninggatan 98", postal: "111 60" }, "something.with.periods": "some value", id: 4711, createdAt: "1970-01-01 00:00" }; validate.cleanAttributes(attributes, whitelist); // => { // name: "Nicklas", // address: { // street: "Drottninggatan 98", // postal: "111 60" // }, // "something.with.periods": "some value" // } var constraints = { name: { presence: true }, "address.street": {}, "address.postal": {}, "something\\.with\\.periods": {} }; validate.cleanAttributes(attributes, constraints); // => { // name: "Nicklas", // address: { // street: "Drottninggatan 98", // postal: "111 60" // }, // "something.with.periods": "some value" // }
collectFormValuesvalidate.collectFormValues(rootElement, [options])
One of the most common tasks is collecting the values and it was
only recently this was possible in a native way
(FormData)
so as a convenience a function for doing this has been added to
validate.js
This function will find all named inputs (inputs that specify the
name attribute) and collect their values.
The given element can be a regular DOM or jQuery element and can
be doesn't have to be a form element.
The following options exists:
- nullify
- Converts empty strings to
null
(default is true) - trim
- Trims whitespace from the start and end of the value
You can ignore inputs by adding the data-ignored
attribute.
<codeclass="lang-markup"><form id="login"> <input type="text" name="username" value="ansman"> <input type="password" name="password" value="correcthorsebatterystaple"> <input type="checkbox" name="remember-me" checked> <input type="hidden" name="some-hidden-value" data-ignored> </form> <script> var form = document.querySelector("form#login"); validate.collectFormValues(form); // => {username: "ansman", password: "correcthorsebatterystaple", remember-me: false} </script>
containsvalidate.contains(collection, value)
Check if the given value exists in the given collection.
Both arrays and objects are supported.
<codeclass="lang-js">validate.contains({}, "foo"); // => false validate.contains({foo: "bar"}, "foo"); // => true validate.contains([1, 2, 3], 4); // => false validate.contains([1, 2, 3], 3); // => true
extendvalidate.extend(object, otherObjects...)
A clone from underscore's extend. It will copy all attributes
from the given objects to the first argument and return the
first argument.
This can be used to do a shallow copy of objects by calling
it with {}
as the first argument.
<codeclass="lang-js">var o1 = {foo: "bar"} , o2 = {baz: "quux"}; validate.extend(o1, o2) === o1; // => true o1; // => {foo: "bar", baz: "quux"}; o2; // => {bar: "quux"}; // Makes a copy of o1, doesn't modify o1 validate.extend({}, o1); // => {foo: "bar", baz: "quux"}; // o1 is not touched validate.extend({}, o1) === o1; // => false
formatvalidate.format(formatString, values)
This function allows you do perform basic string substitution.
It simply finds all %{...}
and replaces them with
the value in the values object.
The values are converted to strings using the string constructor.
If you want to have the %{...}
literal simply prefix
it with a single %
.
<codeclass="lang-js">validate.format("Hi, my name is %{name}", {name: "Nicklas"}); // => "Hi, my name is Nicklas" validate.format("%%{this} will not be replaced", {this: "that"}); // => "%{this} will not be replaced"
getDeepObjectValuevalidate.getDeepObjectValue(object, keypath)
A function that returns attributes from object. If the key
contains a period (.
) it looks for the attribute
in a nested object. Attributes containing a period can be accessed
by escaping the period with a \
.
<codeclass="lang-js">validate.getDeepObjectValue({foo: "bar"}, "foo"); // => "bar" validate.getDeepObjectValue({foo: {bar: {baz: "quux"}}}, "foo.bar.baz"); // => "quux" validate.getDeepObjectValue({"foo.bar": "baz"}, "foo\\.bar"); // => "baz"
isArrayvalidate.isArray(value)
Check if the given value is an array.
<codeclass="lang-js">validate.isArray({}); // => false validate.isArray([]); // => true
isBooleanvalidate.isBoolean(value)
Check if the given value is a boolean.
<codeclass="lang-js">validate.isBoolean("true"); // => false validate.isBoolean(true); // => true
isDatevalidate.isDate(value)
Check if the given value is a Date
instance.
<codeclass="lang-js">validate.isDate(new Date()); // => true validate.isDate(null); // => false validate.isDate({}); // => false
isDefinedvalidate.isDefined(value)
Check if the given value is not null
orundefined
.
<codeclass="lang-js">validate.isDefined("foobar"); // => true validate.isDefined(null); // => false validate.isDefined(undefined); // => false
isDomElementvalidate.isDomElement(value)
Check if the given value is a DOM element.
This function does slightly more than to just check if it's a DOM
element. It also checks that the object supportsquerySelector
and querySelectorAll
which
is used in the project.
Things like jQuery elements are not considered DOM elements.
<codeclass="lang-js">validate.isDomElement({}); // => false validate.isDomElement(document.createElement("div")); // => true
isEmptyvalidate.isEmpty(value)
Check if the given value is non empty. The following value are
considered empty:
null
undefined
- Empty strings
- Whitespace only strings
- Empty arrays
- Empty objects
<codeclass="lang-js">validate.isEmpty({}); // => true validate.isEmpty(null); // => true validate.isEmpty(""); // => true validate.isEmpty(" "); // => true validate.isEmpty("foo"); // => false validate.isEmpty({foo: "bar"}); // => false
isFunctionvalidate.isFunction(value)
Check if the given value is a function. If this returnstrue
the value will be callable.
<codeclass="lang-js">validate.isFunction("foobar"); // => false validate.isFunction(function() {}); // => true
isHashvalidate.isHash(value)
Check if the given value is a hash (a plain object, not an array
or function).
<codeclass="lang-js">validate.isHash([]); // => false validate.isHash({foo: "bar"}); // => true
isIntegervalidate.isInteger(value)
Check if the given value is an integer. If this returns trueisNumber
will also return true.
<codeclass="lang-js">validate.isInteger("foobar"); // => false validate.isInteger(3.14); // => false validate.isInteger(3); // => true
isNumbervalidate.isNumber(value)
Check if the given value is a number. Unlike mostisNumber
checks this function does not considerNaN
to be a number.
<codeclass="lang-js">validate.isNumber("foobar"); // => false validate.isNumber(3.14); // => true
isObjectvalidate.isObject(value)
Check if the given value is an object. This function considers
arrays objects so be careful if this matters to you.
<codeclass="lang-js">validate.isObject("foobar"); // => false validate.isObject({}); // => true validate.isObject([]); // => true
isPromisevalidate.isPromise(value)
Check if the given value is a promise. This used the same
semantics as the ECMAScript spec which means that any non empty
object that has a .then
function is a promise.
<codeclass="lang-js">validate.isPromise({}); // => false validate.isPromise(new Promise(function() {})); // => true validate.isPromise({then: function() {}}); // => true
isStringvalidate.isString(value)
Check if the given value is a string.
<codeclass="lang-js">validate.isString(""); // => true validate.isString({}); // => false
prettifyvalidate.prettify(string)
Provides a way to clean up strings so that they become human
readable.
It is meant to prettify things like attribute names and other
programming related entities. It will do the following things:
- Split words divided by
.
- Remove backslashes
- Replace
_
and-
with spaces - Split cameled cased words
- Make the whole string lower case
- Converts number to strings with no more than 2 decimals
- Calls
toString
on objects - Joins arrays with
,
and calls prettify on all items
Important! It does not removing leading or trailing period
since these are not considered separators.
<codeclass="lang-js">validate.prettify("This.is_a-weirdString\\."); // => "this is a weird string."
resultvalidate.result(value, [arguments...])
Calls the value with the specified arguments and returns the
result if it's a function otherwise it simply returns the value.
This is used in validate.js in places where for example options
can be either an object or a function returning the options.
Important! Since the function is detached it is not
called with a specific context, therefor this only works when the
value is a pure function.
<codeclass="lang-js">// Not a function, returns the first argument validate.result("foobar", 1, 2); // => "foobar" // Returns the result of Math.max(1, 2) validate.result(Math.max, 1, 2); // => 2 // Doesn't work since String#toUpperCase is not a pure function validate.result("foo".toUpperCase); // => Uncaught TypeError: String.prototype.toUpperCase called on null or undefined
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论