Skip to content

Commit f80de58

Browse files
committed
[2.3.1] Fixed form submission when async validation in progress
1 parent d6c7483 commit f80de58

File tree

8 files changed

+125
-29
lines changed

8 files changed

+125
-29
lines changed

CHANGELOG.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,17 @@
1+
## 2.3.1
2+
3+
### Fixed
4+
5+
- Form submission when async validate in progress
6+
7+
How to test:
8+
9+
1. Open [Inline Validators Form](https://detools.github.io/vue-form/#/inline-validators-form)
10+
2. Type `123456` => click `Submit`
11+
3. You will get an async error — form won't submit
12+
4. Type `github` => click `Submit`
13+
5. Form will be submitted after async form validation
14+
115
## 2.3.0
216

317
### Added

README.md

Lines changed: 1 addition & 0 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.1](/CHANGELOG.md#231)
8182
- [2.3.0](/CHANGELOG.md#230)
8283
- [2.2.0](/CHANGELOG.md#220)
8384
- [2.1.0](/CHANGELOG.md#210)

VueForm/Form.vue

Lines changed: 47 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,10 @@ export default {
4242
default: noop,
4343
},
4444
handleModelChange: Function,
45-
handleDisabled: Function,
45+
handleDisabled: {
46+
type: Function,
47+
default: noop,
48+
},
4649
handleReset: Function,
4750
4851
validate: Function,
@@ -55,6 +58,7 @@ export default {
5558
state: {},
5659
syncErrors: {},
5760
asyncErrors: {},
61+
asyncValidations: {},
5862
form: {
5963
submitting: false,
6064
validating: false,
@@ -120,10 +124,7 @@ export default {
120124
121125
const setError = nextValue => {
122126
if (validators) {
123-
const offValidating = this.manageValidatingState()
124127
const error = validate(validators, nextValue, name)
125-
offValidating()
126-
127128
const method = error ? vm.$set : vm.$delete
128129
129130
method(vm.syncErrors, name, error)
@@ -137,12 +138,15 @@ export default {
137138
138139
const setAsyncError = () => {
139140
if (!this.syncErrors[name] && asyncValidators) {
140-
const offValidating = this.manageValidatingState()
141+
const promise = asyncValidate(asyncValidators, this.state[name], name)
142+
const off = this.manageValidatingState(name, promise)
141143
142-
return asyncValidate(asyncValidators, this.state[name], name)
144+
promise
143145
.then(on.success)
144146
.catch(on.error)
145-
.then(offValidating)
147+
.then(off)
148+
149+
return promise
146150
}
147151
148152
return Promise.resolve()
@@ -151,6 +155,11 @@ export default {
151155
const setValue = nextValue => {
152156
vm.$set(this.state, name, nextValue)
153157
158+
// When control value changes we need to clean async errors
159+
if (this.asyncErrors[name]) {
160+
vm.$delete(this.asyncErrors, name)
161+
}
162+
154163
if (this.handleModelChange) {
155164
this.handleModelChange(this.state)
156165
}
@@ -165,6 +174,7 @@ export default {
165174
const cleanFormValue = () => {
166175
vm.$delete(this.state, name)
167176
vm.$delete(this.syncErrors, name)
177+
vm.$delete(this.asyncErrors, name)
168178
}
169179
170180
return {
@@ -179,11 +189,13 @@ export default {
179189
}
180190
},
181191
182-
manageValidatingState() {
192+
manageValidatingState(name, promise) {
183193
this.form.validating = true
194+
this.$set(this.asyncValidations, name, promise)
184195
185196
return () => {
186197
this.form.validating = false
198+
this.$delete(this.asyncValidations, name)
187199
}
188200
},
189201
@@ -195,15 +207,28 @@ export default {
195207
}
196208
},
197209
210+
handleFormDisabled(errors) {
211+
this.handleDisabled(errors || { ...this.syncErrors, ...this.asyncErrors })
212+
},
213+
198214
nativeOnSubmit(event) {
199215
event.preventDefault()
200216
217+
// Just do not anything some form process in progress
218+
if (this.form.submitting) {
219+
return false
220+
}
221+
222+
const isSubmitButtonClick = event.type === 'click'
223+
224+
// Form Level Sync Validate
201225
if (this.validate) {
202226
const syncErrors = this.validate(this.state)
203227
204228
if (!isEmpty(syncErrors)) {
205229
this.syncErrors = syncErrors
206-
return false
230+
231+
return this.handleFormDisabled(syncErrors)
207232
}
208233
209234
this.syncErrors = {}
@@ -212,20 +237,29 @@ export default {
212237
// If Invalid
213238
// There is no SAVE BUTTON
214239
// There is a handleDisabled handler
215-
if (!this.isValid && !this.save && this.handleDisabled) {
216-
return this.handleDisabled({ ...this.syncErrors, ...this.asyncErrors })
240+
if (!this.isValid && isSubmitButtonClick) {
241+
return this.handleFormDisabled()
217242
}
218243
219244
const messages = this.messages || {}
245+
220246
const off = this.manageSubmittingState()
221-
const submitPromise = Promise.resolve(
247+
const submitForm = () => Promise.resolve(
222248
this.handleSubmit({ ...this.initialValues, ...this.state })
223249
)
224250
251+
const submitPromise = this.form.validating
252+
? Promise.all(Object.values(this.asyncValidations)).then(submitForm)
253+
: submitForm()
254+
225255
// Just subscribe to promise, do not catch errors
226256
submitPromise.then(
227257
() => Notification.success(messages.success),
228-
() => Notification.error(messages.error)
258+
() => {
259+
Notification.error(messages.error)
260+
261+
this.handleFormDisabled()
262+
}
229263
).then(off)
230264
231265
return submitPromise

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: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,17 +54,17 @@
5454
}
5555

5656

57-
.buttons[data-v-ebfc5fc8] {
57+
.buttons[data-v-01bb0c7a] {
5858
display: flex;
5959
flex-direction: row;
6060
flex-wrap: no-wrap;
6161
justify-content: flex-start;
6262
align-items: flex-start;
6363
}
64-
.buttons_center[data-v-ebfc5fc8] {
64+
.buttons_center[data-v-01bb0c7a] {
6565
justify-content: center;
6666
}
67-
.buttons_end[data-v-ebfc5fc8] {
67+
.buttons_end[data-v-01bb0c7a] {
6868
justify-content: flex-end;
6969
}
7070

docs/vendors~main.bundle.js

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

example/src/forms/InlineValidatorsForm/InlineValidatorsForm.js

Lines changed: 55 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
import Form, { Input, validators } from '@detools/vue-form'
1+
import Form, { Input, Notification, validators } from '@detools/vue-form'
22

33
export default {
44
data() {
55
return {
66
formValues: {},
7+
formErrors: {},
78
}
89
},
910

@@ -12,15 +13,41 @@ export default {
1213
this.formValues = values
1314
},
1415

15-
asyncValidator(value, name) {
16+
handleReset() {
17+
this.formValues = {}
18+
},
19+
20+
handleDisabled(errors) {
21+
Notification.warning('handleDisabled method has been called')
22+
23+
this.formErrors = errors
24+
},
25+
26+
asyncValidator3000(value, name) {
1627
return new Promise((resolve, reject) => {
1728
setTimeout(() => {
1829
if (value === 'github') {
30+
Notification.success(`${name} passed a validation (3s)`)
31+
resolve()
32+
} else {
33+
Notification.error(`${name} did not pass a validation (3s)`)
34+
reject(`${name} should be github`)
35+
}
36+
}, 3000)
37+
})
38+
},
39+
40+
asyncValidator5000(value, name) {
41+
return new Promise((resolve, reject) => {
42+
setTimeout(() => {
43+
if (value) {
44+
Notification.success(`${name} passed a validation (5s)`)
1945
resolve()
2046
} else {
21-
reject(`${name} should be "github"`)
47+
Notification.error(`${name} did not pass a validation (5s)`)
48+
reject(`${name} is required`)
2249
}
23-
}, 2000)
50+
}, 5000)
2451
})
2552
},
2653
},
@@ -31,13 +58,25 @@ export default {
3158
<h1>Inline Validators Form</h1>
3259
<div class="wrapper">
3360
<div class="form">
34-
<Form reset save submit handleSubmit={this.handleSubmit}>
61+
<Form
62+
reset
63+
save
64+
submit
65+
handleSubmit={this.handleSubmit}
66+
handleReset={this.handleReset}
67+
handleDisabled={this.handleDisabled}>
3568
<Input
3669
formItem
37-
name="asyncUsername"
38-
label="Username"
70+
name="username"
71+
label="Username with async validator for 3s"
3972
validators={[validators.isRequired(), validators.length({ min: 6 })]}
40-
asyncValidators={[this.asyncValidator]}
73+
asyncValidators={[this.asyncValidator3000]}
74+
/>
75+
<Input
76+
formItem
77+
name="anything"
78+
label="Anything with async validator for 5s"
79+
asyncValidators={[this.asyncValidator5000]}
4180
/>
4281
</Form>
4382
</div>
@@ -48,6 +87,14 @@ export default {
4887
<div>
4988
<pre>{JSON.stringify(this.formValues, null, 2)}</pre>
5089
</div>
90+
<br />
91+
<br />
92+
<strong>Form Errors</strong>
93+
<br />
94+
<br />
95+
<div>
96+
<pre>{JSON.stringify(this.formErrors, null, 2)}</pre>
97+
</div>
5198
</div>
5299
</div>
53100
</div>

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@detools/vue-form",
3-
"version": "2.3.0",
3+
"version": "2.3.1",
44
"description": "Form State Management for VueJS",
55
"main": "VueForm/index.js",
66
"scripts": {

0 commit comments

Comments
 (0)