Skip to content

Commit ea2998a

Browse files
committed
feat(QForm): new component -- still WIP
1 parent 6e5e0ff commit ea2998a

File tree

4 files changed

+195
-43
lines changed

4 files changed

+195
-43
lines changed
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
<template>
2+
<div class="q-pa-md" style="max-width: 300px">
3+
<div>{{ native }}</div>
4+
<div>{{ name }}</div>
5+
<div>{{ age }}</div>
6+
<div>{{ modelAsync }}</div>
7+
8+
<q-form
9+
ref="form"
10+
@submit="onSubmit"
11+
@reset="onReset"
12+
@validation-error="onValidationError"
13+
class="q-gutter-md"
14+
>
15+
<input v-model="native">
16+
17+
<q-input
18+
ref="name"
19+
filled
20+
v-model="name"
21+
label="Your name *"
22+
hint="Name and surname"
23+
lazy-rules
24+
:rules="[ val => val && val.length > 0 || 'Please type something']"
25+
/>
26+
27+
<q-input
28+
ref="age"
29+
filled
30+
type="number"
31+
v-model="age"
32+
label="Your age *"
33+
lazy-rules
34+
:rules="[
35+
val => val !== null && val !== '' || 'Please type your age',
36+
val => val > 0 && val < 100 || 'Please type a real age'
37+
]"
38+
/>
39+
40+
<q-input
41+
v-model="modelAsync"
42+
filled
43+
label="Only async *"
44+
:rules="[
45+
asyncRule
46+
]"
47+
/>
48+
49+
<q-toggle v-model="accept" label="I accept the license and terms" />
50+
51+
<div>
52+
<q-btn label="Submit" type="submit" color="primary" />
53+
<q-btn label="Reset" type="reset" color="primary" flat class="q-ml-sm" />
54+
</div>
55+
</q-form>
56+
</div>
57+
</template>
58+
59+
<script>
60+
export default {
61+
data () {
62+
return {
63+
native: null,
64+
name: null,
65+
age: null,
66+
modelAsync: null,
67+
68+
accept: false
69+
}
70+
},
71+
72+
methods: {
73+
async asyncRule (val) {
74+
return new Promise((resolve, reject) => {
75+
setTimeout(() => {
76+
resolve(!!val || '* Required')
77+
}, 1000)
78+
})
79+
},
80+
81+
onSubmit () {
82+
console.log('@submit')
83+
},
84+
85+
onReset () {
86+
this.native = null
87+
console.log('@reset')
88+
},
89+
90+
onValidationError () {
91+
console.log('@validation-error')
92+
}
93+
}
94+
}
95+
</script>

quasar/src/components/form/QForm.js

Lines changed: 79 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,66 +1,108 @@
11
import Vue from 'vue'
2-
import slot from 'quasar/src/utils/slot.js'
2+
3+
import { stopAndPrevent } from '../../utils/event.js'
4+
import slot from '../../utils/slot.js'
35

46
export default Vue.extend({
57
name: 'QForm',
68

9+
mounted () {
10+
this.validateIndex = 0
11+
},
12+
713
methods: {
814
validate () {
9-
let value = true
15+
const promises = []
16+
17+
this.validateIndex++
18+
1019
for (let i = 0; i < this.$children.length; ++i) {
11-
const component = this.$children[i]
12-
if ('validate' in component && typeof component.validate === 'function') {
13-
if (!component.validate()) {
14-
value = false
20+
const comp = this.$children[i]
21+
22+
if (typeof comp.validate === 'function') {
23+
const valid = comp.validate()
24+
25+
if (typeof valid.then === 'function') {
26+
promises.push(valid)
27+
}
28+
else if (valid !== true) {
29+
return false
1530
}
1631
}
1732
}
18-
return value
33+
34+
if (promises.length === 0) {
35+
return true
36+
}
37+
38+
const index = this.validateIndex
39+
40+
return Promise.all(promises).then(
41+
res => {
42+
if (index === this.validateIndex) {
43+
return res
44+
}
45+
},
46+
() => {
47+
if (index === this.validateIndex) {
48+
return false
49+
}
50+
}
51+
)
1952
},
53+
2054
resetValidation () {
55+
this.validateIndex++
56+
2157
for (let i = 0; i < this.$children.length; ++i) {
22-
const component = this.$children[i]
23-
if ('resetValidation' in component && typeof component.resetValidation === 'function') {
24-
component.resetValidation()
58+
const comp = this.$children[i]
59+
if (typeof comp.resetValidation === 'function') {
60+
comp.$emit('input', null)
61+
this.$nextTick(() => {
62+
comp.resetValidation()
63+
})
2564
}
2665
}
2766
},
28-
__onSubmit (event) {
29-
// Abort if the element emitting the event is not
30-
// the element the event is bound to
31-
if (event.target !== event.currentTarget) return
32-
// Stop event propagation
33-
event.stopPropagation()
34-
// Prevent the default handler for this element
35-
event.preventDefault()
36-
if (this.validate()) {
37-
this.$emit('submit')
38-
} else {
39-
this.$emit('error')
67+
68+
submit (evt) {
69+
evt !== void 0 && stopAndPrevent(evt)
70+
71+
const validate = this.validate()
72+
73+
const update = val => {
74+
if (val === true) {
75+
this.$emit('submit')
76+
}
77+
else if (val === false) {
78+
this.$emit('validation-error')
79+
}
4080
}
41-
},
42-
__onReset (event) {
43-
// Abort if the element emitting the event is not
44-
// the element the event is bound to
45-
if (event.target !== event.currentTarget) return
46-
// Stop event propagation
47-
event.stopPropagation()
48-
// Prevent the default handler for this element
49-
event.preventDefault()
50-
if (this.resetValidation()) {
51-
this.$emit('reset')
81+
82+
if (typeof validate.then !== 'function') {
83+
update(validate)
84+
}
85+
else {
86+
validate.then(val => {
87+
update(val[0])
88+
})
5289
}
90+
},
91+
92+
reset () {
93+
this.resetValidation()
94+
this.$emit('reset')
5395
}
5496
},
5597

5698
render (h) {
5799
return h('form', {
58100
staticClass: 'q-form',
59101
on: {
60-
submit: this.__onSubmit,
61-
reset: this.__onReset
102+
...this.$listeners,
103+
submit: this.submit,
104+
reset: this.reset
62105
}
63-
}, slot(this, "default"))
106+
}, slot(this, 'default'))
64107
}
65108
})
66-

quasar/src/components/form/QForm.json

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,26 @@
44
"desc": "Anything can go into this slot"
55
}
66
},
7+
78
"events": {
89
"submit": {
910
"desc": "Emitted when all validations have passed when tethered to a submit button"
1011
},
11-
"error": {
12+
13+
"validation-error": {
1214
"desc": "Emitted when one or more validations have failed"
1315
},
16+
1417
"reset": {
15-
"desc": "Emitted when all calidations have been reset when tethered to a reset button"
18+
"desc": "Emitted when all validations have been reset when tethered to a reset button"
1619
}
1720
},
21+
1822
"methods": {
1923
"validate": {
2024
"desc": "Validates all applicable child components"
2125
},
26+
2227
"resetValidation": {
2328
"desc": "Resets the validation status for all applicable child components"
2429
}

quasar/src/mixins/validate.js

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -66,9 +66,15 @@ export default {
6666
this.innerErrorMessage = void 0
6767
},
6868

69+
/*
70+
* Return value
71+
* - true (validation succeeded)
72+
* - false (validation failed)
73+
* - Promise (pending async validation)
74+
*/
6975
validate (val = this.value) {
7076
if (!this.rules || this.rules.length === 0) {
71-
return
77+
return true
7278
}
7379

7480
this.validateIndex++
@@ -107,7 +113,7 @@ export default {
107113

108114
if (res === false || typeof res === 'string') {
109115
update(true, res)
110-
return
116+
return false
111117
}
112118
else if (res !== true && res !== void 0) {
113119
promises.push(res)
@@ -116,7 +122,7 @@ export default {
116122

117123
if (promises.length === 0) {
118124
update(false)
119-
return
125+
return true
120126
}
121127

122128
if (this.innerLoading !== true) {
@@ -125,22 +131,26 @@ export default {
125131

126132
const index = this.validateIndex
127133

128-
Promise.all(promises).then(
134+
return Promise.all(promises).then(
129135
res => {
130136
if (index === this.validateIndex) {
131137
if (res === void 0 || Array.isArray(res) === false || res.length === 0) {
132138
update(false)
139+
return true
133140
}
134141
else {
135142
const msg = res.find(r => r === false || typeof r === 'string')
136143
update(msg !== void 0, msg)
144+
return msg === void 0
137145
}
138146
}
147+
return true
139148
},
140149
(e) => {
141150
if (index === this.validateIndex) {
142151
console.error(e)
143152
update(true)
153+
return false
144154
}
145155
}
146156
)

0 commit comments

Comments
 (0)