Skip to content
This repository has been archived by the owner on Dec 25, 2017. It is now read-only.

Commit

Permalink
feat(validations): add manually validate API
Browse files Browse the repository at this point in the history
Closes #150
  • Loading branch information
kazupon committed Jan 31, 2016
1 parent 49b663e commit c68fe28
Show file tree
Hide file tree
Showing 6 changed files with 306 additions and 0 deletions.
5 changes: 5 additions & 0 deletions src/validations/base.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,11 @@ export default class BaseValidation {
}
}

willUpdateFlags () {
this.willUpdateDirty(this._el)
this.willUpdateModified(this._el)
}

willUpdateTouched (el, type) {
if (type && type === 'blur') {
this.touched = true
Expand Down
7 changes: 7 additions & 0 deletions src/validations/checkbox.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,13 @@ export default class CheckboxValidation extends BaseValidation {
this._validator.validate()
}

willUpdateFlags () {
each(this._inits, (item, index) => {
this.willUpdateDirty(item.el)
this.willUpdateModified(item.el)
}, this)
}

reset () {
this.resetFlags()
each(this._inits, (item, index) => {
Expand Down
7 changes: 7 additions & 0 deletions src/validations/radio.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,13 @@ export default class RadioValidation extends BaseValidation {
this._validator.validate()
}

willUpdateFlags () {
each(this._inits, (item, index) => {
this.willUpdateDirty(item.el)
this.willUpdateModified(item.el)
}, this)
}

reset () {
this.resetFlags()
each(this._inits, (item, index) => {
Expand Down
35 changes: 35 additions & 0 deletions src/validator.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,23 @@ export default class Validator {
}

enableReactive () {
// define the validation scope
util.Vue.util.defineReactive(this._dir.vm, this.name, this._scope)
this._dir.vm._validatorMaps[this.name] = this

// define the validation reset meta method to vue instance
this._dir.vm.$validatorReset = util.Vue.util.bind(() => {
this.resetValidation()
}, this)

// define the validate manually meta method to vue instance
this._dir.vm.$validate = util.Vue.util.bind((field) => {
this._validate(field)
}, this)
}

disableReactive () {
this._dir.vm.$validate = null
this._dir.vm.$validatorReset = null
this._dir.vm._validatorMaps[this.name] = null
this._dir.vm[this.name] = null
Expand All @@ -65,6 +73,33 @@ export default class Validator {
}, this)
}

_validate (field) {
let validation = this._validations[field]
if (!validation && this._checkboxValidations[field]) {
validation = this._checkboxValidations[field].validation
} else if (!validation && this._radioValidations[field]) {
validation = this._radioValidations[field].validation
}

if (validation) {
validation.willUpdateFlags()
let res = validation.validate()
util.Vue.set(this._scope, field, res)

if (this._scope.dirty) {
this._fireEvent('dirty')
}

if (this._modified !== this._scope.modified) {
this._fireEvent('modified', this._scope.modified)
this._modified = this._scope.modified
}

let valid = this._scope.valid
this._fireEvent((valid ? 'valid' : 'invalid'))
}
}

resetValidation () {
each(this._validations, (validation, key) => {
validation.reset()
Expand Down
1 change: 1 addition & 0 deletions test/specs/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,4 @@ require('./checkbox')
require('./radio')
require('./select')
require('./reset')
require('./validate')
251 changes: 251 additions & 0 deletions test/specs/validate.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,251 @@
import assert from 'power-assert'
import Vue from 'vue'


describe('$validate', () => {
let el, vm

beforeEach(() => {
el = document.createElement('div')
})


describe('text', () => {
beforeEach((done) => {
el.innerHTML =
'<validator name="validator1">' +
'<form novalidate>' +
'<input type="number" v-validate:field1="{ required: true, min: 0, max: 10 }">' +
'<input type="text" value="hello" v-validate:field2="{ minlength: 4 }">' +
'</form>' +
'</validator>'
vm = new Vue({ el: el })
vm.$nextTick(done)
})

it('should be validated', (done) => {
assert(vm.$validator1.field1.required === true)
assert(vm.$validator1.field1.min === false)
assert(vm.$validator1.field1.max === false)
assert(vm.$validator1.field1.valid === false)
assert(vm.$validator1.field1.dirty === false)
assert(vm.$validator1.field1.modified === false)
assert(vm.$validator1.field1.touched === false)
assert(vm.$validator1.field2.minlength === false)
assert(vm.$validator1.field2.valid === true)
assert(vm.$validator1.field2.dirty === false)
assert(vm.$validator1.field2.modified === false)
assert(vm.$validator1.field2.touched === false)
assert(vm.$validator1.valid === false)
assert(vm.$validator1.dirty === false)
assert(vm.$validator1.modified === false)
assert(vm.$validator1.touched === false)

let field1 = el.getElementsByTagName('input')[0]
let field2 = el.getElementsByTagName('input')[1]
field1.value = '11'
field2.value = 'hi'
vm.$nextTick(() => {
vm.$validate('field1')
vm.$validate('field2')

assert(vm.$validator1.field1.required === false)
assert(vm.$validator1.field1.min === false)
assert(vm.$validator1.field1.max === true)
assert(vm.$validator1.field1.valid === false)
assert(vm.$validator1.field1.dirty === true)
assert(vm.$validator1.field1.modified === true)
assert(vm.$validator1.field1.touched === false)
assert(vm.$validator1.field2.minlength === true)
assert(vm.$validator1.field2.valid === false)
assert(vm.$validator1.field2.dirty === true)
assert(vm.$validator1.field2.modified === true)
assert(vm.$validator1.field2.touched === false)
assert(vm.$validator1.valid === false)
assert(vm.$validator1.dirty === true)
assert(vm.$validator1.modified === true)
assert(vm.$validator1.touched === false)

done()
})
})
})


describe('checkbox', () => {
beforeEach((done) => {
el.innerHTML =
'<validator name="validator1">' +
'<form novalidate>' +
'<input type="checkbox" value="foo" v-validate:field1="{ required: true, minlength: 1 }">' +
'<input type="checkbox" value="bar" v-validate:field1>' +
'<input type="checkbox" value="buz" v-validate:field1>' +
'</form>' +
'</validator>'
vm = new Vue({ el: el })
vm.$nextTick(done)
})

it('should be validated', (done) => {
assert(vm.$validator1.field1.required === true)
assert(vm.$validator1.field1.minlength === true)
assert(vm.$validator1.field1.valid === false)
assert(vm.$validator1.field1.touched === false)
assert(vm.$validator1.field1.dirty === false)
assert(vm.$validator1.field1.modified === false)
assert(vm.$validator1.valid === false)
assert(vm.$validator1.dirty === false)
assert(vm.$validator1.modified === false)
assert(vm.$validator1.touched === false)

let checkbox1 = el.getElementsByTagName('input')[0]
let checkbox2 = el.getElementsByTagName('input')[1]
checkbox1.checked = true
checkbox2.checked = true
vm.$nextTick(() => {
vm.$validate('field1')

assert(vm.$validator1.field1.required === false)
assert(vm.$validator1.field1.minlength === false)
assert(vm.$validator1.field1.valid === true)
assert(vm.$validator1.field1.touched === false)
assert(vm.$validator1.field1.dirty === true)
assert(vm.$validator1.field1.modified === true)
assert(vm.$validator1.valid === true)
assert(vm.$validator1.dirty === true)
assert(vm.$validator1.modified === true)
assert(vm.$validator1.touched === false)

done()
})
})
})


describe('radio', () => {
beforeEach((done) => {
el.innerHTML =
'<validator name="validator1">' +
'<form novalidate>' +
'<fieldset>' +
'<label for="radio1">radio1</label>' +
'<input type="radio" id="radio1" name="r1" checked value="foo" v-validate:field1="{ required: true }">' +
'<label for="radio2">radio2</label>' +
'<input type="radio" id="radio2" name="r1" value="bar" v-validate:field1="{ required: true }">' +
'</fieldset>' +
'<fieldset>' +
'<label for="radio3">radio3</label>' +
'<input type="radio" id="radio3" name="r2" value="buz" v-validate:field2="{ required: true }">' +
'<label for="radio4">radio4</label>' +
'<input type="radio" id="radio4" name="r2" value="hoge" v-validate:field2="{ required: true }">' +
'</fieldset>' +
'</form>' +
'</validator>'
vm = new Vue({ el: el })
vm.$nextTick(done)
})

it('should be validated', (done) => {
// default
assert(vm.$validator1.field1.required === false)
assert(vm.$validator1.field1.valid === true)
assert(vm.$validator1.field1.touched === false)
assert(vm.$validator1.field1.dirty === false)
assert(vm.$validator1.field1.modified === false)
assert(vm.$validator1.field2.required === true)
assert(vm.$validator1.field2.valid === false)
assert(vm.$validator1.field2.touched === false)
assert(vm.$validator1.field2.dirty === false)
assert(vm.$validator1.field2.modified === false)
assert(vm.$validator1.valid === false)
assert(vm.$validator1.touched === false)
assert(vm.$validator1.dirty === false)
assert(vm.$validator1.modified === false)

// change
let radio2 = el.getElementsByTagName('input')[1]
let radio3 = el.getElementsByTagName('input')[2]
radio2.checked = true
radio3.checked = true
vm.$nextTick(() => {
vm.$validate('field1')
vm.$validate('field2')

assert(vm.$validator1.field1.required === false)
assert(vm.$validator1.field1.valid === true)
assert(vm.$validator1.field1.touched === false)
assert(vm.$validator1.field1.dirty === true)
assert(vm.$validator1.field1.modified === true)
assert(vm.$validator1.field2.required === false)
assert(vm.$validator1.field2.valid === true)
assert(vm.$validator1.field2.touched === false)
assert(vm.$validator1.field2.dirty === true)
assert(vm.$validator1.field2.modified === true)
assert(vm.$validator1.valid === true)
assert(vm.$validator1.touched === false)
assert(vm.$validator1.dirty === true)
assert(vm.$validator1.modified === true)

done()
})
})
})


describe('select', () => {
beforeEach((done) => {
el.innerHTML =
'<validator name="validator1">' +
'<form novalidate>' +
'<select multiple v-validate:lang="{ required: true, minlength: 2 }">' +
'<option value="en">english</option>' +
'<option value="ja">japanese</option>' +
'<option value="zh">chinese</option>' +
'<option value="fr">french</option>' +
'<option value="de">German</option>' +
'</select>' +
'</form>' +
'</validator>'
vm = new Vue({
el: el
})
vm.$nextTick(done)
})

it('should be validated', (done) => {
// default
assert(vm.$validator1.lang.required === true)
assert(vm.$validator1.lang.minlength === true)
assert(vm.$validator1.lang.valid === false)
assert(vm.$validator1.lang.touched === false)
assert(vm.$validator1.lang.dirty === false)
assert(vm.$validator1.lang.modified === false)
assert(vm.$validator1.valid === false)
assert(vm.$validator1.touched === false)
assert(vm.$validator1.dirty === false)
assert(vm.$validator1.modified === false)

// change
let option2 = el.getElementsByTagName('option')[1]
let option3 = el.getElementsByTagName('option')[2]
option2.selected = true
option3.selected = true
vm.$nextTick(() => {
vm.$validate('lang')

assert(vm.$validator1.lang.required === false)
assert(vm.$validator1.lang.minlength === false)
assert(vm.$validator1.lang.valid === true)
assert(vm.$validator1.lang.touched === false)
assert(vm.$validator1.lang.dirty === true)
assert(vm.$validator1.lang.modified === true)
assert(vm.$validator1.valid === true)
assert(vm.$validator1.touched === false)
assert(vm.$validator1.dirty === true)
assert(vm.$validator1.modified === true)

done()
})
})
})
})

0 comments on commit c68fe28

Please sign in to comment.