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

Commit 9ade590

Browse files
committed
fix(validate): cannot compile validator when using v-for and v-model
Closes #140
1 parent bf6e7d0 commit 9ade590

File tree

8 files changed

+199
-68
lines changed

8 files changed

+199
-68
lines changed

src/directives/validate.js

Lines changed: 124 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,59 +1,158 @@
1-
import { warn, attr, each } from '../util'
1+
import { warn, each } from '../util'
22

33

44
export default function (Vue) {
55

66
const _ = Vue.util
77
const vIf = Vue.directive('if')
8+
const FragmentFactory = Vue.FragmentFactory
9+
10+
// register `v-validate` as terminal directive
811
Vue.compiler.terminalDirectives.push('validate')
912

13+
/**
14+
* `v-validate` directive
15+
*/
16+
1017
Vue.directive('validate', {
1118
priority: vIf.priority + 1,
1219
params: ['group', 'field'],
1320

1421
bind () {
15-
let vm = this.vm
16-
let validatorName = vm.$options._validator
22+
if (this.el.__vue__) {
23+
warn(
24+
'v-validate="' + this.expression + '" cannot be ' +
25+
'used on an instance root element.'
26+
)
27+
return
28+
}
29+
30+
let validatorName = this.vm.$options._validator
1731
if (!validatorName) {
18-
// TODO: should be implemented error message
19-
warn('TODO: should be implemented error message')
32+
warn(
33+
'v-validate need to use into validator element directive: ' +
34+
'(e.g. <validator name="validator">' +
35+
'<input type="text" v-validate:field1="[\'required\']">' +
36+
'</validator>).'
37+
)
2038
return
2139
}
2240

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

25-
let field = this.field = _.camelize(this.arg ? this.arg : this.params.field)
26-
let validation = this.validation = validator.manageValidation(field, vm, this.el, this._scope)
43+
this.setupFragment()
44+
this.setupValidate(validatorName, this.model)
45+
this.listen()
46+
},
47+
48+
update (value, old) {
49+
if (!value) { return }
2750

28-
if (this.params.group) {
29-
validator.addGroupValidation(this.params.group, this.field)
51+
if (_.isPlainObject(value)) {
52+
this.handleObject(value)
53+
} else if (Array.isArray(value)) {
54+
this.handleArray(value)
3055
}
3156

32-
let model = attr(this.el, 'v-model')
33-
this.on('blur', _.bind(validation.listener, validation))
34-
if ((this.el.type === 'checkbox'
35-
|| this.el.type === 'radio'
36-
|| this.el.tagName === 'SELECT') && !model) {
37-
this.on('change', _.bind(validation.listener, validation))
57+
this.validator.validate(this.validation)
58+
},
59+
60+
unbind () {
61+
this.unlisten()
62+
this.teardownValidate()
63+
this.teardownFragment()
64+
65+
this.model = null
66+
},
67+
68+
setupValidate (name, model) {
69+
let params = this.params
70+
let validator = this.validator = this.vm._validatorMaps[name]
71+
72+
this.field = _.camelize(this.arg ? this.arg : params.field)
73+
74+
this.validation = validator.manageValidation(
75+
this.field, model, this.vm, this.frag.node, this._scope
76+
)
77+
78+
if (params.group) {
79+
validator.addGroupValidation(params.group, this.field)
80+
}
81+
},
82+
83+
listen () {
84+
let model = this.model
85+
let validation = this.validation
86+
let el = this.frag.node
87+
88+
this.onBlur = _.bind(validation.listener, validation)
89+
_.on(el, 'blur', this.onBlur)
90+
if ((el.type === 'checkbox'
91+
|| el.type === 'radio'
92+
|| el.tagName === 'SELECT') && !model) {
93+
this.onChange = _.bind(validation.listener, validation)
94+
_.on(el, 'change', this.onChange)
3895
} else {
3996
if (!model) {
40-
this.on('input', _.bind(validation.listener, validation))
97+
this.onInput = _.bind(validation.listener, validation)
98+
_.on(el, 'input', this.onInput)
4199
}
42100
}
43101
},
44102

45-
update (value, old) {
46-
if (!value) {
47-
return
103+
unlisten () {
104+
let el = this.frag.node
105+
106+
if (this.onInput) {
107+
_.off(el, 'input', this.onInput)
108+
this.onInput = null
48109
}
49110

50-
if (_.isPlainObject(value)) {
51-
this.handleObject(value)
52-
} else if (Array.isArray(value)) {
53-
this.handleArray(value)
111+
if (this.onChange) {
112+
_.off(el, 'change', this.onChange)
113+
this.onChange = null
54114
}
55115

56-
this.validator.validate(this.validation)
116+
if (this.onBlur) {
117+
_.off(el, 'blur', this.onBlur)
118+
this.onBlur = null
119+
}
120+
},
121+
122+
teardownValidate () {
123+
if (this.validator && this.validation) {
124+
let el = this.frag.node
125+
126+
if (this.params.group) {
127+
this.validator.removeGroupValidation(this.params.group, this.field)
128+
}
129+
130+
this.validator.unmanageValidation(this.field, el)
131+
132+
this.validator = null
133+
this.validation = null
134+
this.field = null
135+
}
136+
},
137+
138+
setupFragment () {
139+
this.anchor = _.createAnchor('v-validate')
140+
_.replace(this.el, this.anchor)
141+
142+
this.factory = new FragmentFactory(this.vm, this.el)
143+
this.frag = this.factory.create(this._host, this._scope, this._frag)
144+
this.frag.before(this.anchor)
145+
},
146+
147+
teardownFragment () {
148+
if (this.frag) {
149+
this.frag.remove()
150+
this.frag = null
151+
this.factory = null
152+
}
153+
154+
_.replace(this.anchor, this.el)
155+
this.anchor = null
57156
},
58157

59158
handleArray (value) {
@@ -73,18 +172,6 @@ export default function (Vue) {
73172
this.validation.setValidation(key, val)
74173
}
75174
}, this)
76-
},
77-
78-
unbind () {
79-
if (this.validator && this.validation) {
80-
if (this.params.group) {
81-
this.validator.removeGroupValidation(this.params.group, this.field)
82-
}
83-
84-
this.validator.unmanageValidation(this.field, this.el)
85-
this.validator = null
86-
this.validation = null
87-
}
88175
}
89176
})
90177
}

src/validations/base.js

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import util, { empty, each, attr, trigger } from '../util'
1+
import util, { empty, each, trigger } from '../util'
22

33

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

88
export default class BaseValidation {
99

10-
constructor (field, vm, el, scope, validator) {
10+
constructor (field, model, vm, el, scope, validator) {
1111
this.field = field
1212
this.touched = false
1313
this.dirty = false
1414
this.modified = false
1515

16+
this._model = model
1617
this._validator = validator
1718
this._vm = vm
1819
this._el = el
@@ -34,14 +35,15 @@ export default class BaseValidation {
3435
const _ = util.Vue.util
3536

3637
let scope = this._getScope()
37-
let model = attr(el, 'v-model')
38+
let model = this._model
3839
if (model) {
3940
el.value = scope.$get(model) || ''
4041
this._unwatch = scope.$watch(model, _.bind((val, old) => {
42+
console.log('BaseValidation#manageElement $watch', model, val, old)
4143
if (val !== old) {
4244
this.handleValidate(el)
4345
}
44-
}, this))
46+
}, this), { deep: true })
4547
}
4648
}
4749

src/validations/checkbox.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import util, { each, attr } from '../util'
1+
import util, { each } from '../util'
22
import BaseValidation from './base'
33

44

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

99
export default class CheckboxValidation extends BaseValidation {
1010

11-
constructor (field, vm, el, scope, validator) {
12-
super(field, vm, el, scope, validator)
11+
constructor (field, model, vm, el, scope, validator) {
12+
super(field, model, vm, el, scope, validator)
1313

1414
this._inits = []
1515
}
@@ -38,7 +38,7 @@ export default class CheckboxValidation extends BaseValidation {
3838

3939
let item = this._addItem(el)
4040
let scope = this._getScope()
41-
let model = item.model = attr(el, 'v-model')
41+
let model = item.model = this._model
4242
if (model) {
4343
let value = scope.$get(model)
4444
if (Array.isArray(value)) {

src/validations/radio.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import util, { each, attr } from '../util'
1+
import util, { each } from '../util'
22
import BaseValidation from './base'
33

44

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

99
export default class RadioValidation extends BaseValidation {
1010

11-
constructor (field, vm, el, scope, validator) {
12-
super(field, vm, el, scope, validator)
11+
constructor (field, model, vm, el, scope, validator) {
12+
super(field, model, vm, el, scope, validator)
1313

1414
this._inits = []
1515
}
@@ -38,7 +38,7 @@ export default class RadioValidation extends BaseValidation {
3838

3939
let item = this._addItem(el)
4040
let scope = this._getScope()
41-
let model = item.model = attr(el, 'v-model')
41+
let model = item.model = this._model
4242
if (model) {
4343
let value = scope.$get(model)
4444
this._setChecked(value, el, item)

src/validations/select.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import util, { attr } from '../util'
1+
import util from '../util'
22
import BaseValidation from './base'
33

44

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

99
export default class SelectValidation extends BaseValidation {
1010

11-
constructor (field, vm, el, scope, validator) {
12-
super(field, vm, el, scope, validator)
11+
constructor (field, model, vm, el, scope, validator) {
12+
super(field, model, vm, el, scope, validator)
1313

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

4646
let scope = this._getScope()
47-
let model = attr(el, 'v-model')
47+
let model = this._model
4848
if (model) {
4949
let value = scope.$get(model)
5050
let values = !Array.isArray(value) ? [value] : value

src/validator.js

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -55,17 +55,17 @@ export default class Validator {
5555
return ret
5656
}
5757

58-
manageValidation (field, vm, el, scope) {
58+
manageValidation (field, model, vm, el, scope) {
5959
let validation = null
6060

6161
if (el.tagName === 'SELECT') {
62-
validation = this._manageSelectValidation(field, vm, el, scope)
62+
validation = this._manageSelectValidation(field, model, vm, el, scope)
6363
} else if (el.type === 'checkbox') {
64-
validation = this._manageCheckboxValidation(field, vm, el, scope)
64+
validation = this._manageCheckboxValidation(field, model, vm, el, scope)
6565
} else if (el.type === 'radio') {
66-
validation = this._manageRadioValidation(field, vm, el, scope)
66+
validation = this._manageRadioValidation(field, model, vm, el, scope)
6767
} else {
68-
validation = this._manageBaseValidation(field, vm, el, scope)
68+
validation = this._manageBaseValidation(field, model, vm, el, scope)
6969
}
7070

7171
return validation
@@ -83,8 +83,8 @@ export default class Validator {
8383
}
8484
}
8585

86-
_manageBaseValidation (field, vm, el, scope) {
87-
let validation = this._validations[field] = new BaseValidation(field, vm, el, scope, this)
86+
_manageBaseValidation (field, model, vm, el, scope) {
87+
let validation = this._validations[field] = new BaseValidation(field, model, vm, el, scope, this)
8888
validation.manageElement(el)
8989
return validation
9090
}
@@ -99,10 +99,10 @@ export default class Validator {
9999
}
100100
}
101101

102-
_manageCheckboxValidation (field, vm, el, scope) {
102+
_manageCheckboxValidation (field, model, vm, el, scope) {
103103
let validationSet = this._checkboxValidations[field]
104104
if (!validationSet) {
105-
let validation = new CheckboxValidation(field, vm, el, scope, this)
105+
let validation = new CheckboxValidation(field, model, vm, el, scope, this)
106106
validationSet = { validation: validation, elements: 0 }
107107
this._checkboxValidations[field] = validationSet
108108
}
@@ -125,10 +125,10 @@ export default class Validator {
125125
}
126126
}
127127

128-
_manageRadioValidation (field, vm, el, scope) {
128+
_manageRadioValidation (field, model, vm, el, scope) {
129129
let validationSet = this._radioValidations[field]
130130
if (!validationSet) {
131-
let validation = new RadioValidation(field, vm, el, scope, this)
131+
let validation = new RadioValidation(field, model, vm, el, scope, this)
132132
validationSet = { validation: validation, elements: 0 }
133133
this._radioValidations[field] = validationSet
134134
}
@@ -151,8 +151,8 @@ export default class Validator {
151151
}
152152
}
153153

154-
_manageSelectValidation (field, vm, el, scope) {
155-
let validation = this._validations[field] = new SelectValidation(field, vm, el, scope, this)
154+
_manageSelectValidation (field, model, vm, el, scope) {
155+
let validation = this._validations[field] = new SelectValidation(field, model, vm, el, scope, this)
156156
validation.manageElement(el)
157157
return validation
158158
}

0 commit comments

Comments
 (0)