Skip to content

Commit d744b8a

Browse files
authored
fix(runtime-dom): v-model should support number modifier with select tag (#2308)
close #2252
1 parent 3d3323f commit d744b8a

File tree

2 files changed

+107
-2
lines changed

2 files changed

+107
-2
lines changed

packages/runtime-dom/__tests__/directives/vModel.spec.ts

+102
Original file line numberDiff line numberDiff line change
@@ -681,6 +681,108 @@ describe('vModel', () => {
681681
expect(bar.selected).toEqual(true)
682682
})
683683

684+
it('v-model.number should work with select tag', async () => {
685+
const component = defineComponent({
686+
data() {
687+
return { value: null }
688+
},
689+
render() {
690+
return [
691+
withVModel(
692+
h(
693+
'select',
694+
{
695+
value: null,
696+
'onUpdate:modelValue': setValue.bind(this)
697+
},
698+
[h('option', { value: '1' }), h('option', { value: '2' })]
699+
),
700+
this.value,
701+
{
702+
number: true
703+
}
704+
)
705+
]
706+
}
707+
})
708+
render(h(component), root)
709+
710+
const input = root.querySelector('select')
711+
const one = root.querySelector('option[value="1"]')
712+
const data = root._vnode.component.data
713+
714+
one.selected = true
715+
triggerEvent('change', input)
716+
await nextTick()
717+
expect(typeof data.value).toEqual('number')
718+
expect(data.value).toEqual(1)
719+
})
720+
721+
it('v-model.number should work with multiple select', async () => {
722+
const component = defineComponent({
723+
data() {
724+
return { value: [] }
725+
},
726+
render() {
727+
return [
728+
withVModel(
729+
h(
730+
'select',
731+
{
732+
value: null,
733+
multiple: true,
734+
'onUpdate:modelValue': setValue.bind(this)
735+
},
736+
[h('option', { value: '1' }), h('option', { value: '2' })]
737+
),
738+
this.value,
739+
{
740+
number: true
741+
}
742+
)
743+
]
744+
}
745+
})
746+
render(h(component), root)
747+
748+
const input = root.querySelector('select')
749+
const one = root.querySelector('option[value="1"]')
750+
const two = root.querySelector('option[value="2"]')
751+
const data = root._vnode.component.data
752+
753+
one.selected = true
754+
two.selected = false
755+
triggerEvent('change', input)
756+
await nextTick()
757+
expect(data.value).toMatchObject([1])
758+
759+
one.selected = false
760+
two.selected = true
761+
triggerEvent('change', input)
762+
await nextTick()
763+
expect(data.value).toMatchObject([2])
764+
765+
one.selected = true
766+
two.selected = true
767+
triggerEvent('change', input)
768+
await nextTick()
769+
expect(data.value).toMatchObject([1, 2])
770+
771+
one.selected = false
772+
two.selected = false
773+
data.value = [1]
774+
await nextTick()
775+
expect(one.selected).toEqual(true)
776+
expect(two.selected).toEqual(false)
777+
778+
one.selected = false
779+
two.selected = false
780+
data.value = [1, 2]
781+
await nextTick()
782+
expect(one.selected).toEqual(true)
783+
expect(two.selected).toEqual(true)
784+
})
785+
684786
it('should work with composition session', async () => {
685787
const component = defineComponent({
686788
data() {

packages/runtime-dom/src/directives/vModel.ts

+5-2
Original file line numberDiff line numberDiff line change
@@ -166,11 +166,14 @@ export const vModelRadio: ModelDirective<HTMLInputElement> = {
166166
}
167167

168168
export const vModelSelect: ModelDirective<HTMLSelectElement> = {
169-
created(el, binding, vnode) {
169+
created(el, { modifiers: { number } }, vnode) {
170170
addEventListener(el, 'change', () => {
171171
const selectedVal = Array.prototype.filter
172172
.call(el.options, (o: HTMLOptionElement) => o.selected)
173-
.map(getValue)
173+
.map(
174+
(o: HTMLOptionElement) =>
175+
number ? toNumber(getValue(o)) : getValue(o)
176+
)
174177
el._assign(el.multiple ? selectedVal : selectedVal[0])
175178
})
176179
el._assign = getModelAssigner(vnode)

0 commit comments

Comments
 (0)