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

Commit

Permalink
fix(validate): cannot compile validator when using v-for and v-model
Browse files Browse the repository at this point in the history
Closes #140
  • Loading branch information
kazupon committed Jan 22, 2016
1 parent bf6e7d0 commit 9ade590
Show file tree
Hide file tree
Showing 8 changed files with 199 additions and 68 deletions.
161 changes: 124 additions & 37 deletions src/directives/validate.js
Original file line number Diff line number Diff line change
@@ -1,59 +1,158 @@
import { warn, attr, each } from '../util'
import { warn, each } from '../util'


export default function (Vue) {

const _ = Vue.util
const vIf = Vue.directive('if')
const FragmentFactory = Vue.FragmentFactory

// register `v-validate` as terminal directive
Vue.compiler.terminalDirectives.push('validate')

/**
* `v-validate` directive
*/

Vue.directive('validate', {
priority: vIf.priority + 1,
params: ['group', 'field'],

bind () {
let vm = this.vm
let validatorName = vm.$options._validator
if (this.el.__vue__) {
warn(
'v-validate="' + this.expression + '" cannot be ' +
'used on an instance root element.'
)
return
}

let validatorName = this.vm.$options._validator
if (!validatorName) {
// TODO: should be implemented error message
warn('TODO: should be implemented error message')
warn(
'v-validate need to use into validator element directive: ' +
'(e.g. <validator name="validator">' +
'<input type="text" v-validate:field1="[\'required\']">' +
'</validator>).'
)
return
}

let validator = this.validator = this.vm._validatorMaps[validatorName]
this.model = this.el.getAttribute('v-model')

let field = this.field = _.camelize(this.arg ? this.arg : this.params.field)
let validation = this.validation = validator.manageValidation(field, vm, this.el, this._scope)
this.setupFragment()
this.setupValidate(validatorName, this.model)
this.listen()
},

update (value, old) {
if (!value) { return }

if (this.params.group) {
validator.addGroupValidation(this.params.group, this.field)
if (_.isPlainObject(value)) {
this.handleObject(value)
} else if (Array.isArray(value)) {
this.handleArray(value)
}

let model = attr(this.el, 'v-model')
this.on('blur', _.bind(validation.listener, validation))
if ((this.el.type === 'checkbox'
|| this.el.type === 'radio'
|| this.el.tagName === 'SELECT') && !model) {
this.on('change', _.bind(validation.listener, validation))
this.validator.validate(this.validation)
},

unbind () {
this.unlisten()
this.teardownValidate()
this.teardownFragment()

this.model = null
},

setupValidate (name, model) {
let params = this.params
let validator = this.validator = this.vm._validatorMaps[name]

this.field = _.camelize(this.arg ? this.arg : params.field)

this.validation = validator.manageValidation(
this.field, model, this.vm, this.frag.node, this._scope
)

if (params.group) {
validator.addGroupValidation(params.group, this.field)
}
},

listen () {
let model = this.model
let validation = this.validation
let el = this.frag.node

this.onBlur = _.bind(validation.listener, validation)
_.on(el, 'blur', this.onBlur)
if ((el.type === 'checkbox'
|| el.type === 'radio'
|| el.tagName === 'SELECT') && !model) {
this.onChange = _.bind(validation.listener, validation)
_.on(el, 'change', this.onChange)
} else {
if (!model) {
this.on('input', _.bind(validation.listener, validation))
this.onInput = _.bind(validation.listener, validation)
_.on(el, 'input', this.onInput)
}
}
},

update (value, old) {
if (!value) {
return
unlisten () {
let el = this.frag.node

if (this.onInput) {
_.off(el, 'input', this.onInput)
this.onInput = null
}

if (_.isPlainObject(value)) {
this.handleObject(value)
} else if (Array.isArray(value)) {
this.handleArray(value)
if (this.onChange) {
_.off(el, 'change', this.onChange)
this.onChange = null
}

this.validator.validate(this.validation)
if (this.onBlur) {
_.off(el, 'blur', this.onBlur)
this.onBlur = null
}
},

teardownValidate () {
if (this.validator && this.validation) {
let el = this.frag.node

if (this.params.group) {
this.validator.removeGroupValidation(this.params.group, this.field)
}

this.validator.unmanageValidation(this.field, el)

this.validator = null
this.validation = null
this.field = null
}
},

setupFragment () {
this.anchor = _.createAnchor('v-validate')
_.replace(this.el, this.anchor)

this.factory = new FragmentFactory(this.vm, this.el)
this.frag = this.factory.create(this._host, this._scope, this._frag)
this.frag.before(this.anchor)
},

teardownFragment () {
if (this.frag) {
this.frag.remove()
this.frag = null
this.factory = null
}

_.replace(this.anchor, this.el)
this.anchor = null
},

handleArray (value) {
Expand All @@ -73,18 +172,6 @@ export default function (Vue) {
this.validation.setValidation(key, val)
}
}, this)
},

unbind () {
if (this.validator && this.validation) {
if (this.params.group) {
this.validator.removeGroupValidation(this.params.group, this.field)
}

this.validator.unmanageValidation(this.field, this.el)
this.validator = null
this.validation = null
}
}
})
}
10 changes: 6 additions & 4 deletions src/validations/base.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import util, { empty, each, attr, trigger } from '../util'
import util, { empty, each, trigger } from '../util'


/**
Expand All @@ -7,12 +7,13 @@ import util, { empty, each, attr, trigger } from '../util'

export default class BaseValidation {

constructor (field, vm, el, scope, validator) {
constructor (field, model, vm, el, scope, validator) {
this.field = field
this.touched = false
this.dirty = false
this.modified = false

this._model = model
this._validator = validator
this._vm = vm
this._el = el
Expand All @@ -34,14 +35,15 @@ export default class BaseValidation {
const _ = util.Vue.util

let scope = this._getScope()
let model = attr(el, 'v-model')
let model = this._model
if (model) {
el.value = scope.$get(model) || ''
this._unwatch = scope.$watch(model, _.bind((val, old) => {
console.log('BaseValidation#manageElement $watch', model, val, old)
if (val !== old) {
this.handleValidate(el)
}
}, this))
}, this), { deep: true })
}
}

Expand Down
8 changes: 4 additions & 4 deletions src/validations/checkbox.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import util, { each, attr } from '../util'
import util, { each } from '../util'
import BaseValidation from './base'


Expand All @@ -8,8 +8,8 @@ import BaseValidation from './base'

export default class CheckboxValidation extends BaseValidation {

constructor (field, vm, el, scope, validator) {
super(field, vm, el, scope, validator)
constructor (field, model, vm, el, scope, validator) {
super(field, model, vm, el, scope, validator)

this._inits = []
}
Expand Down Expand Up @@ -38,7 +38,7 @@ export default class CheckboxValidation extends BaseValidation {

let item = this._addItem(el)
let scope = this._getScope()
let model = item.model = attr(el, 'v-model')
let model = item.model = this._model
if (model) {
let value = scope.$get(model)
if (Array.isArray(value)) {
Expand Down
8 changes: 4 additions & 4 deletions src/validations/radio.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import util, { each, attr } from '../util'
import util, { each } from '../util'
import BaseValidation from './base'


Expand All @@ -8,8 +8,8 @@ import BaseValidation from './base'

export default class RadioValidation extends BaseValidation {

constructor (field, vm, el, scope, validator) {
super(field, vm, el, scope, validator)
constructor (field, model, vm, el, scope, validator) {
super(field, model, vm, el, scope, validator)

this._inits = []
}
Expand Down Expand Up @@ -38,7 +38,7 @@ export default class RadioValidation extends BaseValidation {

let item = this._addItem(el)
let scope = this._getScope()
let model = item.model = attr(el, 'v-model')
let model = item.model = this._model
if (model) {
let value = scope.$get(model)
this._setChecked(value, el, item)
Expand Down
8 changes: 4 additions & 4 deletions src/validations/select.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import util, { attr } from '../util'
import util from '../util'
import BaseValidation from './base'


Expand All @@ -8,8 +8,8 @@ import BaseValidation from './base'

export default class SelectValidation extends BaseValidation {

constructor (field, vm, el, scope, validator) {
super(field, vm, el, scope, validator)
constructor (field, model, vm, el, scope, validator) {
super(field, model, vm, el, scope, validator)

this._multiple = this._el.hasAttribute('multiple')
}
Expand Down Expand Up @@ -44,7 +44,7 @@ export default class SelectValidation extends BaseValidation {
const _ = util.Vue.util

let scope = this._getScope()
let model = attr(el, 'v-model')
let model = this._model
if (model) {
let value = scope.$get(model)
let values = !Array.isArray(value) ? [value] : value
Expand Down
26 changes: 13 additions & 13 deletions src/validator.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,17 +55,17 @@ export default class Validator {
return ret
}

manageValidation (field, vm, el, scope) {
manageValidation (field, model, vm, el, scope) {
let validation = null

if (el.tagName === 'SELECT') {
validation = this._manageSelectValidation(field, vm, el, scope)
validation = this._manageSelectValidation(field, model, vm, el, scope)
} else if (el.type === 'checkbox') {
validation = this._manageCheckboxValidation(field, vm, el, scope)
validation = this._manageCheckboxValidation(field, model, vm, el, scope)
} else if (el.type === 'radio') {
validation = this._manageRadioValidation(field, vm, el, scope)
validation = this._manageRadioValidation(field, model, vm, el, scope)
} else {
validation = this._manageBaseValidation(field, vm, el, scope)
validation = this._manageBaseValidation(field, model, vm, el, scope)
}

return validation
Expand All @@ -83,8 +83,8 @@ export default class Validator {
}
}

_manageBaseValidation (field, vm, el, scope) {
let validation = this._validations[field] = new BaseValidation(field, vm, el, scope, this)
_manageBaseValidation (field, model, vm, el, scope) {
let validation = this._validations[field] = new BaseValidation(field, model, vm, el, scope, this)
validation.manageElement(el)
return validation
}
Expand All @@ -99,10 +99,10 @@ export default class Validator {
}
}

_manageCheckboxValidation (field, vm, el, scope) {
_manageCheckboxValidation (field, model, vm, el, scope) {
let validationSet = this._checkboxValidations[field]
if (!validationSet) {
let validation = new CheckboxValidation(field, vm, el, scope, this)
let validation = new CheckboxValidation(field, model, vm, el, scope, this)
validationSet = { validation: validation, elements: 0 }
this._checkboxValidations[field] = validationSet
}
Expand All @@ -125,10 +125,10 @@ export default class Validator {
}
}

_manageRadioValidation (field, vm, el, scope) {
_manageRadioValidation (field, model, vm, el, scope) {
let validationSet = this._radioValidations[field]
if (!validationSet) {
let validation = new RadioValidation(field, vm, el, scope, this)
let validation = new RadioValidation(field, model, vm, el, scope, this)
validationSet = { validation: validation, elements: 0 }
this._radioValidations[field] = validationSet
}
Expand All @@ -151,8 +151,8 @@ export default class Validator {
}
}

_manageSelectValidation (field, vm, el, scope) {
let validation = this._validations[field] = new SelectValidation(field, vm, el, scope, this)
_manageSelectValidation (field, model, vm, el, scope) {
let validation = this._validations[field] = new SelectValidation(field, model, vm, el, scope, this)
validation.manageElement(el)
return validation
}
Expand Down
Loading

0 comments on commit 9ade590

Please sign in to comment.