Skip to content

Commit e56f628

Browse files
committed
feat(form components): New prop ("name") useful for form processing quasarframework#5963 (replaces quasarframework#6265)
1 parent 3315f33 commit e56f628

File tree

10 files changed

+108
-86
lines changed

10 files changed

+108
-86
lines changed

ui/dev/src/pages/form/checkbox-radio-toggle-test.vue

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,14 @@
77
<q-card tag="form" @submit.prevent="onSubmit" :dark="dark" :disabled="disable">
88
<q-card-section>
99
<div class="q-mb-lg row q-col-gutter-x-md">
10-
<q-select filled class="col" for="select1" v-model="select1" dense :options="options" :dark="dark" :disable="disable" label="Single" clearable />
11-
<q-select filled class="col" for="select2" v-model="select2" dense :options="options" :dark="dark" :disable="disable" label="Multiple" multiple clearable />
10+
<q-select name="select1" filled class="col" v-model="select1" dense :options="options" :dark="dark" :disable="disable" label="select1 - Single" clearable />
11+
<q-select name="select2" filled class="col" v-model="select2" dense :options="options" :dark="dark" :disable="disable" label="select2 - Multiple" multiple clearable />
1212
</div>
1313

1414
<div class="q-mb-lg row q-col-gutter-x-md">
15-
<q-input filled class="col" for="text1" v-model="text1" dense :dark="dark" :disable="disable" clearable label="Text" />
16-
<q-input filled class="col" for="textarea1" v-model="text2" dense :dark="dark" :disable="disable" clearable type="textarea" autogrow label="Textarea" />
17-
<q-file filled class="col" for="file1" v-model="file" dense :dark="dark" :disable="disable" clearable label="File" />
15+
<q-input name="text1" filled class="col" v-model="text1" dense :dark="dark" :disable="disable" clearable label="text1 - Text" />
16+
<q-input name="textarea1" filled class="col" v-model="text2" dense :dark="dark" :disable="disable" clearable type="textarea" autogrow label="textarea1 - Textarea" />
17+
<q-file name="file1" filled class="col" v-model="file" dense :dark="dark" :disable="disable" clearable label="file1 - File" />
1818
</div>
1919

2020
<div class="q-my-lg">
@@ -162,7 +162,7 @@ export default {
162162
for (const [ name, value ] of formData.entries()) {
163163
submitResult.push({
164164
name,
165-
value: value.name || value
165+
value
166166
})
167167
}
168168
this.submitResult = submitResult

ui/src/components/field/QField.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,9 @@ export default Vue.extend({
5959

6060
autofocus: Boolean,
6161

62-
for: [String],
62+
for: String,
63+
name: String,
64+
6365
maxlength: [Number, String],
6466
maxValues: [Number, String] // private, do not add to JSON; internally needed by QSelect
6567
},
@@ -206,6 +208,10 @@ export default Vue.extend({
206208
value: this.value,
207209
emitValue: this.__emitValue
208210
}
211+
},
212+
213+
nameProp () {
214+
return this.name || this.for
209215
}
210216
},
211217

ui/src/components/field/__QField.json

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -161,10 +161,18 @@
161161

162162
"for": {
163163
"type": "String",
164-
"desc": "DOM element id to be used as 'for' attribute of the label and as 'id' for the focus target",
165-
"examples": [ "for=\"myFieldsId\"" ],
164+
"desc": "Used to specify the 'id' of the control and also the 'for' attribute of the label that wraps it; If no 'name' prop is specified, then it is used for this attribute as well",
165+
"examples": [ "myFieldsId" ],
166166
"category": "behavior",
167167
"addedIn": "v1.4.2"
168+
},
169+
170+
"name": {
171+
"type": "String",
172+
"desc": "Used to specify the name of the control; Useful if dealing with forms; If not specified, it takes the value of 'for' prop, if it exists",
173+
"examples": [ "car_id" ],
174+
"category": "behavior",
175+
"addedIn": "v1.9.0"
168176
}
169177
},
170178

ui/src/components/file/QFile.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,7 @@ export default Vue.extend({
222222
type: 'file',
223223
title: '', // try to remove default tooltip,
224224
accept: this.accept,
225+
name: this.nameProp,
225226
...this.$attrs,
226227
id: this.targetUid,
227228
disabled: this.editable !== true

ui/src/components/input/QInput.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,7 @@ export default Vue.extend({
237237
'data-autofocus': this.autofocus,
238238
rows: this.type === 'textarea' ? 6 : void 0,
239239
'aria-label': this.label,
240+
name: this.nameProp,
240241
...this.$attrs,
241242
id: this.targetUid,
242243
type: this.type,

ui/src/components/radio/QRadio.js

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,6 @@ import { cache } from '../../utils/vm.js'
1010
export default Vue.extend({
1111
name: 'QRadio',
1212

13-
inheritAttrs: false,
14-
1513
mixins: [ DarkMixin, OptionSizeMixin ],
1614

1715
props: {
@@ -22,6 +20,8 @@ export default Vue.extend({
2220
required: true
2321
},
2422

23+
name: String,
24+
2525
label: String,
2626
leftLabel: Boolean,
2727

@@ -62,12 +62,16 @@ export default Vue.extend({
6262
return this.disable === true ? -1 : this.tabindex || 0
6363
},
6464

65-
domProps () {
66-
return {
67-
type: 'radio',
68-
value: this.val === Object(this.val) || this.val,
69-
checked: this.isTrue
70-
}
65+
attrs () {
66+
const prop = { type: 'radio' }
67+
68+
this.name !== void 0 && Object.assign(prop, {
69+
checked: this.isTrue,
70+
name: this.name,
71+
value: this.val
72+
})
73+
74+
return prop
7175
}
7276
},
7377

@@ -108,8 +112,7 @@ export default Vue.extend({
108112
this.disable !== true && content.unshift(
109113
h('input', {
110114
staticClass: 'q-radio__native q-ma-none q-pa-none invisible',
111-
attrs: this.$attrs,
112-
domProps: this.domProps
115+
attrs: this.attrs
113116
})
114117
)
115118

ui/src/components/radio/QRadio.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,14 @@
2222
"category": "model"
2323
},
2424

25+
"name": {
26+
"type": "String",
27+
"desc": "Used to specify the name of the control; Useful if dealing with forms",
28+
"examples": [ "car_id" ],
29+
"category": "behavior",
30+
"addedIn": "v1.9.0"
31+
},
32+
2533
"label": {
2634
"type": "String",
2735
"desc": "Label to display along the radio control (or use the default slot instead of this prop)",

ui/src/components/select/QSelect.js

Lines changed: 41 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -170,12 +170,6 @@ export default Vue.extend({
170170
(this.popupContentClass ? ' ' + this.popupContentClass : '')
171171
},
172172

173-
optionValueKey () {
174-
return typeof this.optionValue === 'string'
175-
? this.optionValue
176-
: 'value'
177-
},
178-
179173
innerValue () {
180174
const
181175
mapNull = this.mapOptions === true && this.multiple !== true,
@@ -240,7 +234,7 @@ export default Vue.extend({
240234
const { from, to } = this.virtualScrollSliceRange
241235

242236
return this.options.slice(from, to).map((opt, i) => {
243-
const disable = this.__isDisabled(opt)
237+
const disable = this.__getOptionDisabled(opt) === true
244238
const index = from + i
245239

246240
const itemProps = {
@@ -300,6 +294,18 @@ export default Vue.extend({
300294
return this.optionsSelectedClass !== void 0
301295
? this.optionsSelectedClass
302296
: (this.color !== void 0 ? `text-${this.color}` : '')
297+
},
298+
299+
__getOptionValue () {
300+
return this.__getPropValueFn('optionValue', 'value')
301+
},
302+
303+
__getOptionLabel () {
304+
return this.__getPropValueFn('optionLabel', 'label')
305+
},
306+
307+
__getOptionDisabled () {
308+
return this.__getPropValueFn('optionDisable', 'disable')
303309
}
304310
},
305311

@@ -354,7 +360,7 @@ export default Vue.extend({
354360
},
355361

356362
toggleOption (opt, keepOpen) {
357-
if (this.editable !== true || opt === void 0 || this.__isDisabled(opt) === true) {
363+
if (this.editable !== true || opt === void 0 || this.__getOptionDisabled(opt) === true) {
358364
return
359365
}
360366

@@ -431,7 +437,7 @@ export default Vue.extend({
431437
this.virtualScrollLength - 1
432438
)
433439
}
434-
while (index !== -1 && index !== this.optionIndex && this.__isDisabled(this.options[index]) === true)
440+
while (index !== -1 && index !== this.optionIndex && this.__getOptionDisabled(this.options[index]) === true)
435441

436442
if (this.optionIndex !== index) {
437443
this.setOptionIndex(index)
@@ -452,38 +458,16 @@ export default Vue.extend({
452458
return this.options.find(fn) || innerValueCache.find(fn) || value
453459
},
454460

455-
__getOptionValue (opt) {
456-
if (typeof this.optionValue === 'function') {
457-
return this.optionValue(opt)
458-
}
459-
if (Object(opt) === opt && this.optionValueKey in opt) {
460-
return opt[this.optionValueKey]
461-
}
462-
return opt
463-
},
464-
465-
__getOptionLabel (opt) {
466-
if (typeof this.optionLabel === 'function') {
467-
return this.optionLabel(opt)
468-
}
469-
if (Object(opt) === opt) {
470-
return typeof this.optionLabel === 'string'
471-
? opt[this.optionLabel]
472-
: opt.label
473-
}
474-
return opt
475-
},
461+
__getPropValueFn (propName, defaultVal) {
462+
const val = this[propName] !== void 0
463+
? this[propName]
464+
: defaultVal
476465

477-
__isDisabled (opt) {
478-
if (typeof this.optionDisable === 'function') {
479-
return this.optionDisable(opt) === true
480-
}
481-
if (Object(opt) === opt) {
482-
return typeof this.optionDisable === 'string'
483-
? opt[this.optionDisable] === true
484-
: opt.disable === true
485-
}
486-
return false
466+
return typeof val === 'function'
467+
? val
468+
: opt => Object(opt) === opt && val in opt
469+
? opt[val]
470+
: opt
487471
},
488472

489473
__isSelected (opt) {
@@ -588,7 +572,7 @@ export default Vue.extend({
588572
index = normalizeToInterval(index + 1, -1, optionsLength - 1)
589573
}
590574
while (index !== this.optionIndex && (
591-
this.__isDisabled(this.options[index]) === true ||
575+
this.__getOptionDisabled(this.options[index]) === true ||
592576
searchRe.test(this.__getOptionLabel(this.options[index])) !== true
593577
))
594578
}
@@ -714,7 +698,7 @@ export default Vue.extend({
714698
return this.selectedScope.map((scope, i) => h(QChip, {
715699
key: 'option-' + i,
716700
props: {
717-
removable: this.__isDisabled(scope.opt) !== true,
701+
removable: this.__getOptionDisabled(scope.opt) !== true,
718702
dense: true,
719703
textColor: this.color,
720704
tabindex: this.computedTabindex
@@ -767,23 +751,23 @@ export default Vue.extend({
767751
}))
768752
}
769753

770-
if (this.disable !== true && this.innerValue.length > 0) {
771-
const options = this.innerValue
772-
.filter(value => Object(value) !== value)
773-
.map(value => h('option', {
774-
domProps: {
775-
value,
776-
selected: true
777-
}
778-
}))
779-
780-
child.push(h('select', {
781-
staticClass: 'hidden',
754+
if (this.disable !== true && this.nameProp !== void 0 && this.innerValue.length > 0) {
755+
const opts = this.innerValue.map(value => h('option', {
782756
attrs: {
783-
name: this.targetUid,
784-
multiple: this.multiple
757+
value,
758+
selected: true
785759
}
786-
}, options))
760+
}))
761+
762+
child.push(
763+
h('select', {
764+
staticClass: 'hidden',
765+
attrs: {
766+
name: this.nameProp,
767+
multiple: this.multiple
768+
}
769+
}, opts)
770+
)
787771
}
788772

789773
return h('div', { staticClass: 'q-field__native row items-center', attrs: this.$attrs }, child)

ui/src/mixins/checkbox.js

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,15 @@ import { cache } from '../utils/vm.js'
99
export default {
1010
mixins: [ DarkMixin, OptionSizeMixin ],
1111

12-
inheritAttrs: false,
13-
1412
props: {
1513
value: {
1614
required: true,
1715
default: null
1816
},
1917
val: {},
2018

19+
name: String,
20+
2121
trueValue: { default: true },
2222
falseValue: { default: false },
2323

@@ -94,12 +94,16 @@ export default {
9494
return `q-${this.type}__inner--${state}${color}`
9595
},
9696

97-
domProps () {
98-
return {
99-
type: 'checkbox',
100-
value: this.trueValue === Object(this.trueValue) || this.trueValue,
101-
checked: this.isIndeterminate === true ? void 0 : this.isTrue
102-
}
97+
attrs () {
98+
const prop = { type: 'checkbox' }
99+
100+
this.name !== void 0 && Object.assign(prop, {
101+
checked: this.isTrue,
102+
name: this.name,
103+
value: this.trueValue
104+
})
105+
106+
return prop
103107
}
104108
},
105109

@@ -159,8 +163,7 @@ export default {
159163
this.disable !== true && inner.unshift(
160164
h('input', {
161165
staticClass: `q-${this.type}__native absolute q-ma-none q-pa-none invisible`,
162-
attrs: this.$attrs,
163-
domProps: this.domProps
166+
attrs: this.attrs
164167
})
165168
)
166169

ui/src/mixins/checkbox.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,14 @@
4747
"category": "behavior"
4848
},
4949

50+
"name": {
51+
"type": "String",
52+
"desc": "Used to specify the name of the control; Useful if dealing with forms",
53+
"examples": [ "car_id" ],
54+
"category": "behavior",
55+
"addedIn": "v1.9.0"
56+
},
57+
5058
"size": {
5159
"addedIn": "v1.8.0"
5260
},

0 commit comments

Comments
 (0)