Skip to content

Commit

Permalink
fix(runtime-dom): v-model.number modifier for single & multi select
Browse files Browse the repository at this point in the history
  • Loading branch information
69hunter committed Oct 4, 2020
1 parent 1abcb2c commit 49df6e0
Show file tree
Hide file tree
Showing 2 changed files with 109 additions and 2 deletions.
102 changes: 102 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,108 @@ describe('vModel', () => {
expect(bar.selected).toEqual(true)
})

it('v-model.number should work with single select', 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('v-model.number should work with multiple select', async () => {
const component = defineComponent({
data() {
return { value: [] }
},
render() {
return [
withVModel(
h(
'select',
{
value: null,
multiple: true,
'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 two = root.querySelector('option[value="2"]')
const data = root._vnode.component.data

one.selected = true
two.selected = false
triggerEvent('change', input)
await nextTick()
expect(data.value).toMatchObject([1])

one.selected = false
two.selected = true
triggerEvent('change', input)
await nextTick()
expect(data.value).toMatchObject([2])

one.selected = true
two.selected = true
triggerEvent('change', input)
await nextTick()
expect(data.value).toMatchObject([1, 2])

one.selected = false
two.selected = false
data.value = [1]
await nextTick()
expect(one.selected).toEqual(true)
expect(two.selected).toEqual(false)

one.selected = false
two.selected = false
data.value = [1, 2]
await nextTick()
expect(one.selected).toEqual(true)
expect(two.selected).toEqual(true)
})

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

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

el._assign(el.multiple ? selectedVal : selectedVal[0])
})
el._assign = getModelAssigner(vnode)
Expand Down

0 comments on commit 49df6e0

Please sign in to comment.