Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(runtime-dom): v-model.number work with select tag #2254

Closed
wants to merge 9 commits into from
37 changes: 37 additions & 0 deletions packages/runtime-dom/__tests__/directives/vModel.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -681,6 +681,43 @@ describe('vModel', () => {
expect(bar.selected).toEqual(true)
})

it('v-model.number should work with select tag', async () => {
const component = defineComponent({
data() {
return { value: null }
},
render() {
return [
withVModel(
h(
'select',
{
value: null,
'onUpdate:modelValue': setValue.bind(this)
},
[h('option', { value: '1' }), h('option', { value: '2' })]
),
this.value,
{
number: true
}
)
]
}
})
render(h(component), root)

const input = root.querySelector('select')
const one = root.querySelector('option[value="1"]')
const data = root._vnode.component.data

one.selected = true
triggerEvent('change', input)
await nextTick()
expect(typeof data.value).toEqual('number')
expect(data.value).toEqual(1)
})

it('should work with composition session', async () => {
const component = defineComponent({
data() {
Expand Down
11 changes: 9 additions & 2 deletions packages/runtime-dom/src/directives/vModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -166,12 +166,19 @@ export const vModelRadio: ModelDirective<HTMLInputElement> = {
}

export const vModelSelect: ModelDirective<HTMLSelectElement> = {
created(el, binding, vnode) {
created(el, { modifiers: { number } }, vnode) {
addEventListener(el, 'change', () => {
const castToNumber = number
const selectedVal = Array.prototype.filter
.call(el.options, (o: HTMLOptionElement) => o.selected)
.map(getValue)
el._assign(el.multiple ? selectedVal : selectedVal[0])

let domValue: string | number = el.multiple ? selectedVal : selectedVal[0]

if (castToNumber) {
domValue = toNumber(domValue)
}
Comment on lines +176 to +180
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@edison1105, I would suggest handling the case of multiple select here.
When the el.multiple is true, domValue will be assigned with an array from selectedVal.
The domValue = toNumber(domValue) will cast an array of numbers to number.

This will make the multiple select case throw an error of:

<select multiple v-model> expects an Array or Set value for its binding, but got Number.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks~ @69hunter. I will update this.

el._assign(domValue)
})
el._assign = getModelAssigner(vnode)
},
Expand Down