Skip to content

Commit

Permalink
fix: handle v-model.trim and v-model.number (#2408)
Browse files Browse the repository at this point in the history
* fix: cast values to numbers before commiting them closes #2403

* fix: trim values before commiting them when v-model.trim is used

* test: added modifier tests

* test: added case for NaN with v-model.number
  • Loading branch information
logaretm committed Oct 8, 2019
1 parent dda9abb commit bf4a566
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 4 deletions.
25 changes: 23 additions & 2 deletions src/utils/events.ts
@@ -1,4 +1,4 @@
import { isCallable, toArray } from './index';
import { isCallable, toArray, isNaN } from './index';

export const isEvent = (evt: any): evt is Event => {
if (!evt) {
Expand All @@ -18,15 +18,36 @@ export const isEvent = (evt: any): evt is Event => {
return false;
};

type BoundInputElement = HTMLInputElement & {
_vModifiers?: { number?: boolean; trim?: boolean };
};

export function normalizeEventValue(value: unknown): any {
if (!isEvent(value)) {
return value;
}

const input = value.target as HTMLInputElement;
const input = value.target as BoundInputElement;
if (input.type === 'file' && input.files) {
return toArray(input.files);
}

// If the input has a `v-model.number` modifier applied.
if (input._vModifiers && input._vModifiers.number) {
// as per the spec the v-model.number uses parseFloat
const valueAsNumber = parseFloat(input.value);
if (isNaN(valueAsNumber)) {
return input.value;
}

return valueAsNumber;
}

if (input._vModifiers && input._vModifiers.trim) {
const trimmedValue = typeof input.value === 'string' ? input.value.trim() : input.value;

return trimmedValue;
}

return input.value;
}
46 changes: 44 additions & 2 deletions tests/providers/provider.js
Expand Up @@ -794,7 +794,7 @@ test('validates manually with a initial value using the validate event handler o
<input type="text" :value="myValue" @input="validate">
<p id="error">{{ errors[0] }}</p>
</ValidationProvider>
</ValidationObserver>
</ValidationObserver>
`
},
{ localVue: Vue, sync: false }
Expand All @@ -819,7 +819,7 @@ test('validates manually with a initial value using the validate event handler o
<ModelComp :value="myValue" @input="validate" />
<p id="error">{{ errors[0] }}</p>
</ValidationProvider>
</ValidationObserver>
</ValidationObserver>
`
},
{ localVue: Vue, sync: false }
Expand Down Expand Up @@ -1110,3 +1110,45 @@ test('returns custom error messages passed in the customMessages prop', async ()

expect(result.errors[0]).toEqual(customMessage);
});

describe('Handle value mutating modifiers', () => {
test('handles .number modifier', () => {
const wrapper = mount(
{
data: () => ({ val: '' }),
template: `
<ValidationProvider rules="required" v-slot="ctx" ref="provider">
<input v-model.number="val" type="text">
</ValidationProvider>
`
},
{ localVue: Vue, sync: false }
);

// should happen synchronously!
wrapper.find('input').setValue('11');
expect(wrapper.vm.$refs.provider.value).toBe(11);

// NaN values are left as is.
wrapper.find('input').setValue('x23');
expect(wrapper.vm.$refs.provider.value).toBe('x23');
});

test('handles .trim modifier', () => {
const wrapper = mount(
{
data: () => ({ val: '' }),
template: `
<ValidationProvider rules="required" v-slot="ctx" ref="provider">
<input v-model.trim="val" type="text">
</ValidationProvider>
`
},
{ localVue: Vue, sync: false }
);

// should happen synchronously!
wrapper.find('input').setValue(' abc');
expect(wrapper.vm.$refs.provider.value).toBe('abc');
});
});

0 comments on commit bf4a566

Please sign in to comment.