Skip to content

Commit 35622c2

Browse files
committed
[2.3.0] Added Form Level Sync Validation
1 parent fc82886 commit 35622c2

File tree

25 files changed

+378
-228
lines changed

25 files changed

+378
-228
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
## 2.3.0
2+
3+
### Added
4+
5+
- Form level sync validation. [Demo](https://detools.github.io/vue-form/#/sync-validation-form)
6+
17
## 2.2.0
28

39
### Changed

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ See demo at [https://detools.github.io/vue-form](https://detools.github.io/vue-f
7878

7979
## Changelog
8080

81+
- [2.3.0](/CHANGELOG.md#230)
8182
- [2.2.0](/CHANGELOG.md#220)
8283
- [2.1.0](/CHANGELOG.md#210)
8384
- [2.0.0](/CHANGELOG.md#200)
@@ -94,7 +95,6 @@ See demo at [https://detools.github.io/vue-form](https://detools.github.io/vue-f
9495
- `<Upload />`
9596
- `<Rate />`
9697
- Add validation examples
97-
- [Field level sync validation](https://detools.github.io/vue-form/#inline-validators-form)
98-
- Form level sync validation
98+
- [Field level sync validation](https://detools.github.io/vue-form/#/inline-validators-form)
99+
- [Form level sync validation](https://detools.github.io/vue-form/#/sync-validation-form)
99100
- Field level async validation
100-
- Form level async validation

VueForm/ConnectedInput.js

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,7 @@ export default {
2424
autosize: Boolean,
2525
autocomplete: {
2626
type: String,
27-
28-
// Autocomplete === 'off' does not work in Chrome
29-
default: () => 'nope',
27+
default: 'off',
3028
},
3129
readonly: Boolean,
3230
max: Number,

VueForm/ConnectedSelect.js

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,7 @@ export default {
3636

3737
autocomplete: {
3838
type: String,
39-
40-
// Autocomplete === 'off' does not work in Chrome
41-
default: () => 'nope',
39+
default: 'off',
4240
},
4341

4442
disabled: Boolean,

VueForm/Form.vue

Lines changed: 72 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
<script>
2-
import { isNil, isBoolean, has, mapValues, noop } from 'lodash'
2+
import { isNil, isBoolean, isEmpty, has, mapValues, noop } from 'lodash'
33
import { Form, Button } from 'element-ui'
44
import FormItem from './ConnectedFormItem'
55
import Notification from './Notification'
66
import CONSTANTS from './constants'
77
import { validate, asyncValidate } from './validators/validate'
8+
import isValid from './utils/isValid'
89
910
const BUTTONS_POSITION = {
1011
START: 'start',
@@ -52,7 +53,8 @@ export default {
5253
data() {
5354
return {
5455
state: {},
55-
errors: {},
56+
syncErrors: {},
57+
asyncErrors: {},
5658
form: {
5759
submitting: false,
5860
validating: false,
@@ -73,7 +75,38 @@ export default {
7375
7476
computed: {
7577
isValid() {
76-
return !Object.values(this.errors).some(error => !isNil(error))
78+
return isValid([this.syncErrors, this.asyncErrors])
79+
},
80+
81+
isDisabled() {
82+
const { submitting, validating } = this.form
83+
84+
return submitting || validating
85+
},
86+
87+
isSubmitButtonDisabled() {
88+
return this.isDisabled || !this.isValid
89+
},
90+
91+
submitButtonType() {
92+
return this.save ? 'danger' : 'primary'
93+
},
94+
95+
buttons() {
96+
return {
97+
reset: isBoolean(this.reset) ? 'Reset' : this.reset,
98+
save: isBoolean(this.save) ? 'Save' : this.save,
99+
submit: isBoolean(this.submit) ? 'Submit' : this.submit,
100+
}
101+
},
102+
103+
buttonsClassName() {
104+
return [
105+
'buttons', {
106+
buttons_center: this.buttonsPosition === BUTTONS_POSITION.CENTER,
107+
buttons_end: this.buttonsPosition === BUTTONS_POSITION.END,
108+
},
109+
]
77110
},
78111
},
79112
@@ -93,17 +126,17 @@ export default {
93126
94127
const method = error ? vm.$set : vm.$delete
95128
96-
method(vm.errors, name, error)
129+
method(vm.syncErrors, name, error)
97130
}
98131
}
99132
100133
const on = {
101-
success: () => vm.$delete(vm.errors, name),
102-
error: error => vm.$set(vm.errors, name, error),
134+
success: () => vm.$delete(vm.asyncErrors, name),
135+
error: error => vm.$set(vm.asyncErrors, name, error),
103136
}
104137
105138
const setAsyncError = () => {
106-
if (!this.errors[name] && asyncValidators) {
139+
if (!this.syncErrors[name] && asyncValidators) {
107140
const offValidating = this.manageValidatingState()
108141
109142
return asyncValidate(asyncValidators, this.state[name], name)
@@ -131,14 +164,18 @@ export default {
131164
132165
const cleanFormValue = () => {
133166
vm.$delete(this.state, name)
134-
vm.$delete(this.errors, name)
167+
vm.$delete(this.syncErrors, name)
135168
}
136169
137170
return {
138171
cleanFormValue,
139172
setError,
140173
setAsyncError,
141-
useState: () => [this.state[name], setValue, this.errors[name]],
174+
useState: () => [
175+
this.state[name],
176+
setValue,
177+
this.syncErrors[name] || this.asyncErrors[name],
178+
],
142179
}
143180
},
144181
@@ -161,11 +198,22 @@ export default {
161198
nativeOnSubmit(event) {
162199
event.preventDefault()
163200
201+
if (this.validate) {
202+
const syncErrors = this.validate(this.state)
203+
204+
if (!isEmpty(syncErrors)) {
205+
this.syncErrors = syncErrors
206+
return false
207+
}
208+
209+
this.syncErrors = {}
210+
}
211+
164212
// If Invalid
165213
// There is no SAVE BUTTON
166214
// There is a handleDisabled handler
167215
if (!this.isValid && !this.save && this.handleDisabled) {
168-
return this.handleDisabled(this.errors)
216+
return this.handleDisabled({ ...this.syncErrors, ...this.asyncErrors })
169217
}
170218
171219
const messages = this.messages || {}
@@ -192,7 +240,8 @@ export default {
192240
const initialValue = this.initialValues[key]
193241
194242
vm.$set(this.state, key, initialValue || (Array.isArray(value) ? [] : ''))
195-
vm.$delete(this.errors, key)
243+
vm.$delete(this.syncErrors, key)
244+
vm.$delete(this.asyncErrors, key)
196245
})
197246
198247
if (this.handleReset) {
@@ -202,46 +251,32 @@ export default {
202251
203252
reinitializeValues(updatedInitialValues) {
204253
this.state = mapValues(this.state, (value, key) => updatedInitialValues[key])
205-
this.errors = {}
254+
this.syncErrors = {}
255+
this.asyncErrors = {}
206256
},
207257
208258
renderPlainButtons() {
209-
const buttons = {
210-
reset: isBoolean(this.reset) ? 'Reset' : this.reset,
211-
save: isBoolean(this.save) ? 'Save' : this.save,
212-
submit: isBoolean(this.submit) ? 'Submit' : this.submit,
213-
}
214-
215-
const buttonsClassName = [
216-
'buttons', {
217-
buttons_center: this.buttonsPosition === BUTTONS_POSITION.CENTER,
218-
buttons_end: this.buttonsPosition === BUTTONS_POSITION.END,
219-
},
220-
]
221-
222-
const { submitting, validating } = this.form
223-
const disabled = submitting || validating
224-
const submitDisabled = disabled || (!this.isValid && !this.handleDisabled)
225-
226259
return (
227-
<div class={buttonsClassName}>
260+
<div class={this.buttonsClassName}>
228261
{this.reset && (
229-
<Button nativeType="reset" disabled={disabled}>
230-
{buttons.reset}
262+
<Button nativeType="reset" disabled={this.isDisabled}>
263+
{this.buttons.reset}
231264
</Button>
232265
)}
233266
{this.save && (
234-
<Button nativeType="submit" type="primary" disabled={disabled}>
235-
{buttons.save}
267+
<Button nativeType="submit" type="primary" disabled={this.isDisabled}>
268+
{this.buttons.save}
236269
</Button>
237270
)}
238271
{this.submit && (
239272
<Button
240-
type={this.save ? 'danger' : 'primary'}
273+
class={[`el-button--${this.submitButtonType}`, {
274+
'is-disabled': this.isSubmitButtonDisabled,
275+
}]}
276+
type={this.submitButtonType}
241277
nativeType={!this.save ? 'submit' : undefined}
242-
disabled={submitDisabled}
243278
on-click={this.nativeOnSubmit}>
244-
{buttons.submit}
279+
{this.buttons.submit}
245280
</Button>
246281
)}
247282
</div>

VueForm/utils/isValid.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import isNil from 'lodash/isNil'
2+
3+
export default function isValid(errorsArray) {
4+
return !errorsArray.some(errors => Object.values(errors).some(error => !isNil(error)))
5+
}

docs/bundle.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/main.css

Lines changed: 45 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,46 @@
11

2+
.root-container[data-v-6dc3c25e] {
3+
min-height: 100%;
4+
}
5+
.title[data-v-6dc3c25e] {
6+
font-size: 40px;
7+
margin: 10px 0 0;
8+
font-weight: bold;
9+
}
10+
.main-container[data-v-6dc3c25e] {
11+
display: flex;
12+
flex-direction: row;
13+
justify-content: space-between;
14+
align-items: stretch;
15+
}
16+
.aside[data-v-6dc3c25e] {
17+
border-top: 1px solid rgba(0, 0, 0, 0.1);
18+
}
19+
.main[data-v-6dc3c25e] {
20+
padding: 10px 40px 40px;
21+
border-top: 1px solid rgba(0, 0, 0, 0.1);
22+
border-left: 1px solid rgba(0, 0, 0, 0.1);
23+
}
24+
.link[data-v-6dc3c25e] {
25+
display: block;
26+
line-height: 40px;
27+
padding-left: 30px;
28+
position: relative;
29+
color: #0a0a0a;
30+
}
31+
.link_active[data-v-6dc3c25e]:before {
32+
content: '\261B';
33+
position: absolute;
34+
display: block;
35+
width: 10px;
36+
height: 10px;
37+
top: -3px;
38+
left: 5px;
39+
color: black;
40+
font-size: 20px;
41+
}
42+
43+
244
.is-vue-form-warn .el-form-item__error {
345
color: #FF9800;
446
}
@@ -12,74 +54,17 @@
1254
}
1355

1456

15-
.buttons[data-v-929e2c82] {
57+
.buttons[data-v-ebfc5fc8] {
1658
display: flex;
1759
flex-direction: row;
1860
flex-wrap: no-wrap;
1961
justify-content: flex-start;
2062
align-items: flex-start;
2163
}
22-
.buttons_center[data-v-929e2c82] {
64+
.buttons_center[data-v-ebfc5fc8] {
2365
justify-content: center;
2466
}
25-
.buttons_end[data-v-929e2c82] {
67+
.buttons_end[data-v-ebfc5fc8] {
2668
justify-content: flex-end;
2769
}
2870

29-
30-
.wrapper[data-v-5084746c] {
31-
display: flex;
32-
flex-direction: row;
33-
justify-content: space-between;
34-
}
35-
.form[data-v-5084746c] {
36-
width: 750px;
37-
}
38-
.values[data-v-5084746c] {
39-
width: 200px;
40-
}
41-
42-
43-
.wrapper[data-v-5e0e1c8c] {
44-
display: flex;
45-
flex-direction: row;
46-
justify-content: space-between;
47-
}
48-
.form[data-v-5e0e1c8c],
49-
.values[data-v-5e0e1c8c] {
50-
width: 320px;
51-
}
52-
53-
54-
.wrapper[data-v-12049160] {
55-
display: flex;
56-
flex-direction: row;
57-
justify-content: space-between;
58-
}
59-
.form[data-v-12049160],
60-
.values[data-v-12049160] {
61-
width: 320px;
62-
}
63-
64-
65-
.wrapper[data-v-08c02437] {
66-
display: flex;
67-
flex-direction: row;
68-
justify-content: space-between;
69-
}
70-
.form[data-v-08c02437],
71-
.values[data-v-08c02437] {
72-
width: 320px;
73-
}
74-
75-
76-
.forms[data-v-fe917d3c] {
77-
max-width: 1000px;
78-
padding: 0 20px;
79-
}
80-
.divider[data-v-fe917d3c] {
81-
height: 2px;
82-
background-color: #757575;
83-
margin: 50px 0;
84-
}
85-

docs/vendors~main.bundle.js

Lines changed: 8 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)