c6054b50beae82d4cee4f9cf451dc7dcc082707846bc51d30717d9d1b0481f35617cc98baa485437e32db0d178103be7ed231e3b3e77854d4115a7d3ba2bf7 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365
  1. # async-validator
  2. ---
  3. Validate form asynchronous. A variation of https://github.com/freeformsystems/async-validate
  4. [![NPM version][npm-image]][npm-url]
  5. [![build status][travis-image]][travis-url]
  6. [![Test coverage][coveralls-image]][coveralls-url]
  7. [![gemnasium deps][gemnasium-image]][gemnasium-url]
  8. [![node version][node-image]][node-url]
  9. [![npm download][download-image]][download-url]
  10. [npm-image]: http://img.shields.io/npm/v/async-validator.svg?style=flat-square
  11. [npm-url]: http://npmjs.org/package/async-validator
  12. [travis-image]: https://img.shields.io/travis/yiminghe/async-validator.svg?style=flat-square
  13. [travis-url]: https://travis-ci.org/yiminghe/async-validator
  14. [coveralls-image]: https://img.shields.io/coveralls/yiminghe/async-validator.svg?style=flat-square
  15. [coveralls-url]: https://coveralls.io/r/yiminghe/async-validator?branch=master
  16. [gemnasium-image]: http://img.shields.io/gemnasium/yiminghe/async-validator.svg?style=flat-square
  17. [gemnasium-url]: https://gemnasium.com/yiminghe/async-validator
  18. [node-image]: https://img.shields.io/badge/node.js-%3E=4.0.0-green.svg?style=flat-square
  19. [node-url]: http://nodejs.org/download/
  20. [download-image]: https://img.shields.io/npm/dm/async-validator.svg?style=flat-square
  21. [download-url]: https://npmjs.org/package/async-validator
  22. ## API
  23. The following is modified from earlier version of [async-validate](https://github.com/freeformsystems/async-validate).
  24. ### Usage
  25. Basic usage involves defining a descriptor, assigning it to a schema and passing the object to be validated and a callback function to the `validate` method of the schema:
  26. ```javascript
  27. var schema = require('async-validator');
  28. var descriptor = {
  29. name: {type: "string", required: true}
  30. }
  31. var validator = new schema(descriptor);
  32. validator.validate({name: "muji"}, (errors, fields) => {
  33. if(errors) {
  34. // validation failed, errors is an array of all errors
  35. // fields is an object keyed by field name with an array of
  36. // errors per field
  37. return handleErrors(errors, fields);
  38. }
  39. // validation passed
  40. });
  41. ```
  42. ### Validate
  43. ```javascript
  44. function(source, [options], callback)
  45. ```
  46. * `source`: The object to validate (required).
  47. * `options`: An object describing processing options for the validation (optional).
  48. * `callback`: A callback function to invoke when validation completes (required).
  49. ### Options
  50. * `first`: Boolean, Invoke `callback` when the first validation rule generates an error,
  51. no more validation rules are processed.
  52. If your validation involves multiple asynchronous calls (for example, database queries) and you only need the first error use this option.
  53. * `firstFields`: Boolean|String[], Invoke `callback` when the first validation rule of the specified field generates an error,
  54. no more validation rules of the same field are processed. `true` means all fields.
  55. ### Rules
  56. Rules may be functions that perform validation.
  57. ```javascript
  58. function(rule, value, callback, source, options)
  59. ```
  60. * `rule`: The validation rule in the source descriptor that corresponds to the field name being validated. It is always assigned a `field` property with the name of the field being validated.
  61. * `value`: The value of the source object property being validated.
  62. * `callback`: A callback function to invoke once validation is complete. It expects to be passed an array of `Error` instances to indicate validation failure.
  63. * `source`: The source object that was passed to the `validate` method.
  64. * `options`: Additional options.
  65. * `options.messages`: The object containing validation error messages, will be deep merged with defaultMessages.
  66. The options passed to `validate` are passed on to the validation functions so that you may reference transient data (such as model references) in validation functions. However, some option names are reserved; if you use these properties of the options object they are overwritten. The reserved properties are `messages`, `exception` and `error`.
  67. ```javascript
  68. var schema = require('async-validator');
  69. var descriptor = {
  70. name(rule, value, callback, source, options) {
  71. var errors = [];
  72. if(!/^[a-z0-9]+$/.test(value)) {
  73. errors.push(
  74. new Error(
  75. util.format("%s must be lowercase alphanumeric characters",
  76. rule.field)));
  77. }
  78. callback(errors);
  79. }
  80. }
  81. var validator = new schema(descriptor);
  82. validator.validate({name: "Firstname"}, (errors, fields) => {
  83. if(errors) {
  84. return handleErrors(errors, fields);
  85. }
  86. // validation passed
  87. });
  88. ```
  89. It is often useful to test against multiple validation rules for a single field, to do so make the rule an array of objects, for example:
  90. ```javascript
  91. var descriptor = {
  92. email: [
  93. {type: "string", required: true, pattern: schema.pattern.email},
  94. {validator(rule, value, callback, source, options) {
  95. var errors = [];
  96. // test if email address already exists in a database
  97. // and add a validation error to the errors array if it does
  98. callback(errors);
  99. }}
  100. ]
  101. }
  102. ```
  103. #### Type
  104. Indicates the `type` of validator to use. Recognised type values are:
  105. * `string`: Must be of type `string`. `This is the default type.`
  106. * `number`: Must be of type `number`.
  107. * `boolean`: Must be of type `boolean`.
  108. * `method`: Must be of type `function`.
  109. * `regexp`: Must be an instance of `RegExp` or a string that does not generate an exception when creating a new `RegExp`.
  110. * `integer`: Must be of type `number` and an integer.
  111. * `float`: Must be of type `number` and a floating point number.
  112. * `array`: Must be an array as determined by `Array.isArray`.
  113. * `object`: Must be of type `object` and not `Array.isArray`.
  114. * `enum`: Value must exist in the `enum`.
  115. * `date`: Value must be valid as determined by `Date`
  116. * `url`: Must be of type `url`.
  117. * `hex`: Must be of type `hex`.
  118. * `email`: Must be of type `email`.
  119. #### Required
  120. The `required` rule property indicates that the field must exist on the source object being validated.
  121. #### Pattern
  122. The `pattern` rule property indicates a regular expression that the value must match to pass validation.
  123. #### Range
  124. A range is defined using the `min` and `max` properties. For `string` and `array` types comparison is performed against the `length`, for `number` types the number must not be less than `min` nor greater than `max`.
  125. #### Length
  126. To validate an exact length of a field specify the `len` property. For `string` and `array` types comparison is performed on the `length` property, for the `number` type this property indicates an exact match for the `number`, ie, it may only be strictly equal to `len`.
  127. If the `len` property is combined with the `min` and `max` range properties, `len` takes precedence.
  128. #### Enumerable
  129. To validate a value from a list of possible values use the `enum` type with a `enum` property listing the valid values for the field, for example:
  130. ```javascript
  131. var descriptor = {
  132. role: {type: "enum", enum: ['admin', 'user', 'guest']}
  133. }
  134. ```
  135. #### Whitespace
  136. It is typical to treat required fields that only contain whitespace as errors. To add an additional test for a string that consists solely of whitespace add a `whitespace` property to a rule with a value of `true`. The rule must be a `string` type.
  137. You may wish to sanitize user input instead of testing for whitespace, see [transform](#transform) for an example that would allow you to strip whitespace.
  138. #### Deep Rules
  139. If you need to validate deep object properties you may do so for validation rules that are of the `object` or `array` type by assigning nested rules to a `fields` property of the rule.
  140. ```javascript
  141. var descriptor = {
  142. address: {
  143. type: "object", required: true,
  144. fields: {
  145. street: {type: "string", required: true},
  146. city: {type: "string", required: true},
  147. zip: {type: "string", required: true, len: 8, message: "invalid zip"}
  148. }
  149. },
  150. name: {type: "string", required: true}
  151. }
  152. var validator = new schema(descriptor);
  153. validator.validate({ address: {} }, (errors, fields) => {
  154. // errors for street, address.city, address.zip and address.name
  155. });
  156. ```
  157. Note that if you do not specify the `required` property on the parent rule it is perfectly valid for the field not to be declared on the source object and the deep validation rules will not be executed as there is nothing to validate against.
  158. Deep rule validation creates a schema for the nested rules so you can also specify the `options` passed to the `schema.validate()` method.
  159. ```javascript
  160. var descriptor = {
  161. address: {
  162. type: "object", required: true, options: {single: true, first: true},
  163. fields: {
  164. street: {type: "string", required: true},
  165. city: {type: "string", required: true},
  166. zip: {type: "string", required: true, len: 8, message: "invalid zip"}
  167. }
  168. },
  169. name: {type: "string", required: true}
  170. }
  171. var validator = new schema(descriptor);
  172. validator.validate({ address: {} }, (errors, fields) => {
  173. // now only errors for street and name
  174. });
  175. ```
  176. The parent rule is also validated so if you have a set of rules such as:
  177. ```javascript
  178. var descriptor = {
  179. roles: {
  180. type: "array", required: true, len: 3,
  181. fields: {
  182. 0: {type: "string", required: true},
  183. 1: {type: "string", required: true},
  184. 2: {type: "string", required: true}
  185. }
  186. }
  187. }
  188. ```
  189. And supply a source object of `{roles: ["admin", "user"]}` then two errors will be created. One for the array length mismatch and one for the missing required array entry at index 2.
  190. #### defaultField
  191. The `defaultField` property can be used with the `array` or `object` type for validating all values of the container.
  192. It may be an `object` or `array` containing validation rules. For example:
  193. ```javascript
  194. var descriptor = {
  195. urls: {
  196. type: "array", required: true,
  197. defaultField: {type: "url"}
  198. }
  199. }
  200. ```
  201. Note that `defaultField` is expanded to `fields`, see [deep rules](#deep-rules).
  202. #### Transform
  203. Sometimes it is necessary to transform a value before validation, possibly to coerce the value or to sanitize it in some way. To do this add a `transform` function to the validation rule. The property is transformed prior to validation and re-assigned to the source object to mutate the value of the property in place.
  204. ```javascript
  205. var schema = require('async-validator');
  206. var sanitize = require('validator').sanitize;
  207. var descriptor = {
  208. name: {
  209. type: "string",
  210. required: true, pattern: /^[a-z]+$/,
  211. transform(value) {
  212. return sanitize(value).trim();
  213. }
  214. }
  215. }
  216. var validator = new schema(descriptor);
  217. var source = {name: " user "};
  218. validator.validate(source, (errors, fields) => {
  219. assert.equal(source.name, "user");
  220. });
  221. ```
  222. Without the `transform` function validation would fail due to the pattern not matching as the input contains leading and trailing whitespace, but by adding the transform function validation passes and the field value is sanitized at the same time.
  223. ### Messages
  224. Depending upon your application requirements, you may need i18n support or you may prefer different validation error messages.
  225. The easiest way to achieve this is to assign a `message` to a rule:
  226. ```javascript
  227. {name:{type: "string", required: true, message: "Name is required"}}
  228. ```
  229. Message can be any type, such as jsx format.
  230. ```javascript
  231. {name:{type: "string", required: true, message: <b>Name is required</b>}}
  232. ```
  233. Potentially you may require the same schema validation rules for different languages, in which case duplicating the schema rules for each language does not make sense.
  234. In this scenario you could just provide your own messages for the language and assign it to the schema:
  235. ```javascript
  236. var schema = require('async-validator');
  237. var cn = {
  238. required: '%s 必填',
  239. };
  240. var descriptor = {name:{type: "string", required: true}};
  241. var validator = new schema(descriptor);
  242. // deep merge with defaultMessages
  243. validator.messages(cn);
  244. ...
  245. ```
  246. If you are defining your own validation functions it is better practice to assign the message strings to a messages object and then access the messages via the `options.messages` property within the validation function.
  247. ### validator
  248. you can custom validate function for specified field:
  249. ```js
  250. const fields = {
  251. asyncField:{
  252. validator(rule,value,callback){
  253. ajax({
  254. url:'xx',
  255. value:value
  256. }).then(function(data){
  257. callback();
  258. },function(error){
  259. callback(new Error(error))
  260. });
  261. }
  262. },
  263. promiseField:{
  264. validator(rule, value){
  265. return ajax({
  266. url:'xx',
  267. value:value
  268. });
  269. }
  270. }
  271. };
  272. ```
  273. ## Test Case
  274. ```
  275. npm test
  276. npm run chrome-test
  277. ```
  278. ## Coverage
  279. ```
  280. npm run coverage
  281. ```
  282. open coverage/ dir
  283. ## License
  284. Everything is [MIT](http://en.wikipedia.org/wiki/MIT_License).