diff --git a/v2.0-spec.md b/v2.0-spec.md new file mode 100644 index 0000000..cdf38c6 --- /dev/null +++ b/v2.0-spec.md @@ -0,0 +1,477 @@ +# 2.0 spec plan (Draft level) + +- custom element (e.g. ``) + - custom element enable validation result scope that did **inherit** from user data scope. vue-validator do not operate user data via validation result scope + - `id` attribute: keep the validation result data in custom element (e.g. vm.$validators.validator1) + - `name` attribute: change the validator result scope namespace (e.g. default: `validity`) + - available multiple validator (e.g. vm.$validators.validator1, vm.$validators.validator2, ...) +- set custom directive (`v-validate`) to target element + - specify **field name**: keep the validation result + - validation result format: object property base structure (e.g. `validity.field.constraint`) + - accessable validation result with property keypath base (e.g. `validity.username.xxx`) +- support for each field, the following validation property + - `valid` (e.g. `validity.field.valid`) + - `invalid` (reverse of `valid`, e.g. `validity.field.invalid`) + - `touched` (input tag was focused, e.g. `validity.field.touched`) + - `untouched` + - `modified` (from **initial** field value, e.g. `validity.field.modified`) + - `dirty` (angluar-like, attached even **once**, e.g. `validity.field.dirty`) + - `pristine` (angluar-like, **not** attached even once, e.g. `validity.field.pristine`) + - `error` (error message from #51, e.g. `validity.field.error`) +- support the following top level property that keep the validation result of all fields + - `valid` (when **all** property is valid, return `true`) + - `invalid` (if exist even **one** invalid property, return `true`) + - `touched` (if exist even **one** touched property, return `true`) + - `untouched` + - `modified` (if exist even **one** modified property, return `true`) + - `dirty` (if exist even **one** dirty property, return `true`) + - `pristine` (if exist even **one** pristine property, return `true`) + - `submitted` +- build-in validators + - required + - pattern + - min + - max + - minLength + - maxLength +- improve delay validator initialization feature + - custom element base (not for each custom directive) +- validator use HTML5 Form attributes base. (e.g. `min`, `max` ...) + - support custom validator: use attribute (e.g. `myValidator1` -> ``) + - support reactivity & function or inline expression like `v-on`: `{{ mustache }}` expressions (e.g. ``) + - support async validator +- validator assets feature + - aseets management: like vue.js + - register/retrieve custom validator or build-in validtors + +## example + +```html +
+

user registration

+ +
+ username:
+ age:
+ email:
+ password:
+ site:
+
+``` + +```javascript +var Vue = require('vue') +var VueValidator = require('vue-validator') + +// +// register custom validators with validator assets +// + +// url validator, sync validation +VueValidator.asset('url', function (val) { + return /^(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?$/.test(val) +}) + +// exist validator, async validaiton +Vuevalidator.asset('exist', function (val) { + return function (resolve, reject) { + // server-side validation with ajax (e.g. using `fetch` case) + fetch('/validators/exist', { + method: 'post', + headers: { + 'content-type': 'application/json', + 'x-token': 'xxxxxxxx' + }, + body: JSON.stringify({ username: val }) + }).then(function (res) { + if (res.status === 200) { + resolve(true) + } else if (res.status === 400) { + resolve(false) + } + }).catch(function (err) { + // something todo ... + reject(new Error('exist validator fail')) + }) + } +}) + +// email validator, async validation +VueValidator.asset('email', function (val) { + return function (resolve, reject) { + // something todo ... + } +}) + +// install vue-validator +Vue.use(VueValidator) + +// create Vue instance +new Vue({ + data: { + constraints: { + age: { + min: 18, + } + }, + name: '', + age: 18, + address: '', + password: '' + }, + computed: { + constraintAgeMax: function () { + return this.constraints.age.min * 5 + } + } +}).$mount('#app') +``` + + + + +## Basic +- custom element (e.g. ``) + - custom element enable validation result scope. this means validation results scope are isolated from user data scope. + - specify `id` attribute that keep the validation result data in custom element (e.g. vm.$validators.validator1) +- set custom directive (`v-validate`) to target element + - specify **field name** that keep the validation result + - validation result format: object property base structure (e.g. `validity.field.constraint`) + - accessable validation result with property keypath base. (e.g. `validity.username.xxx`) +- validation constraints use HTML5 Form attributes base. (e.g. `min`, `max` ...) + - validation constraint of custome validator: use attribute (e.g. `myValidator1` -> ``) + - support reactivity: spcify `{{ mustache }}` expressions to attribute. (e.g. ``) +- support each field the following property + - `valid` (e.g. `validity.field.valid`) + - `invalid` (e.g. `validity.field.invalid`) + - `modified` (e.g. `validity.field.modified`) + - `dirty` (angluar-like, e.g. `validity.field.dirty`) + - `pristine` (angluar-like, e.g. `validity.field.pristine`) +- support the following top level property that keep the result of all fields + - `valid` + - `invalid` + - `modified` + - `dirty` + - `pristine` +- set `constraints` to `option.validator` field. + - support async loading +- spcify `constraints` to constraint attribute with `{{ mustache }}` expressions. + + +Example: + +```html +
+

user registration

+ +
+ username:
+ age:
+ email:
+ password:
+
+``` + +```javascript +var Vue = require('vue') +var VueValidator = require('vue-validator') + +Vue.use(VueValidator) + +new Vue({ + data: { + username: '', + age: 18, + email: '', + password: '' + } +}).$mount('#app') +``` + + +## Dynamic validation constraint (NEW) +- set `constraints` to `option.validator` field. + - support async loading +- spcify `constraints` to constraint attribute with `{{ mustache }}` expressions. + + +```html +
+

user registration

+ +
+ username:
+ age:
+ email:
+ password:
+
+``` + +```javascript +var Vue = require('vue') +var VueValidator = require('vue-validator') + +Vue.use(VueValidator) + +new Vue({ + data: { + username: '', + age: 18, + email: '', + password: '' + }, + validators: { + validator2: { + // sync + constraints: { + username: { + maxLength: 16 + }, + age: { + min: 18, + max: 100 + }, + email: { + pattern: '' + } + }, + // async + /* + constraints: function (resolve, reject) { + this.$http.get('/users/constraints', function (data, status, request) { + resolve(data) + }).error(function (data, status, request) { + reject(new Error('validation rule download error')) + }) + } + */ + } + }, + ready: function () { + this.$validators.validator2.rules.age.max = 99 + } +}).$mount('#app') +``` + + +## Lazy initialization (CAHNGE) + +```html +
+

user setting

+ +
+ +
+ +
+``` + +```javascript +var Vue = require('vue') +var VueValidator = require('vue-validator') + +Vue.use(VueValidator) + +new Vue({ + data: function () { + // TODO: + // if changed asynchronously resolved data loading in 1.0-beta, should be changed !! + return function (resolve, reject) { + var resource = this.$resource('/users/:id') + resource.get({ id: 1 }, function (data, status, request) { + resolve(data) + }).error(function (data, status, request) { + reject(new Error('fetch failed')) + }) + } + } +}).$mount('#app') +``` + + +## Multiple validation (NEW) +- You can create multiple validation with `v-validator` custom element. + +```html +
+ + +
+ username:
+ +
+ + + + +
+ age:
+ +
+
+ + + +
+ email:
+ +
+
+ + + +
+``` + +```javascript +var Vue = require('vue') +var VueValidator = require('vue-validator') + +Vue.use(VueValidator) + +var vm = new Vue({ + data: { + username: '', + age: 18, + email: '' + }, + validators: { + validator1: { // for validator1 + // ... + }, + validator2: { // for validator2 + // ... + }, + validator3: { // for validator3 + // ... + }, + // ... + }, + computed: { + isInvalid: function () { // check invalid of all validators + return this.$validators.validator1.invalid || + this.$validators.validator2.invalid || + this.$validators.validator3.invalid + } + } +}).$mount('#app') +``` + + +## Build-in validator +- required +- pattern +- min +- max +- minLength +- maxLength +- numeric (NEW) +- integer (NEW) +- float (NEW) +- alpha (NEW) + + +## User custom validator & Validator assets +- You can defined custome validator +- You can register/retrieve custom validator or build-in validtors at validator asset + +```html +
+ +
+ name:
+ address:
+ +
+ required your name. + invalid your email address format. +
+
+
+
+``` + +```javascript +var Vue = require('vue') +var VueValidator = require('vue-validator') + +// register custom validators with validator assets +VueValidator.validator('email', function (val) { // sync validator + return /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/.test(val) +}) +VueValidator.validator('email-async', function (val) { // async validator + // validate at server-side + return function (resolve, reject) { + fetch('/validators/email', { + method: 'post', + headers: { 'content-type': 'application/json' }, + body: JSON.stringify({ email: val }) + }).then(function (res) { + if (res.status === 200) { + resolve(true) + } else if (res.status === 400) { + resolve(false) + } + }).catch(function (err) { + reject(new Error('email validator fail')) + }) + } +}) + +Vue.use(VueValidator) + +new Vue({ + data: { + name: '', + address: '' + } +}).$mount('#app') +```