Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
fix: ensure option bound value type is preserved closes #3440
  • Loading branch information
logaretm committed Aug 13, 2021
1 parent 03d3389 commit b144615
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 4 deletions.
9 changes: 8 additions & 1 deletion packages/vee-validate/src/utils/assertions.ts
Expand Up @@ -54,7 +54,14 @@ export function isNotNestedPath(path: string) {
* Checks if an element is a native HTML5 multi-select input element
*/
export function isNativeMultiSelect(el: HTMLElement): el is HTMLSelectElement {
return el.tagName === 'SELECT' && (el as HTMLSelectElement).multiple;
return isNativeSelect(el) && el.multiple;
}

/**
* Checks if an element is a native HTML5 select input element
*/
export function isNativeSelect(el: HTMLElement): el is HTMLSelectElement {
return el.tagName === 'SELECT';
}

/**
Expand Down
10 changes: 9 additions & 1 deletion packages/vee-validate/src/utils/events.ts
@@ -1,4 +1,4 @@
import { hasCheckedAttr, isNativeMultiSelect, isEvent } from './assertions';
import { hasCheckedAttr, isNativeMultiSelect, isNativeSelect, isEvent } from './assertions';
import { getBoundValue, hasValueBinding } from './vnode';

export function normalizeEventValue(value: Event | unknown): unknown {
Expand All @@ -23,5 +23,13 @@ export function normalizeEventValue(value: Event | unknown): unknown {
.map(getBoundValue);
}

// makes sure we get the actual `option` bound value
// #3440
if (isNativeSelect(input)) {
const selectedOption = Array.from(input.options).find(opt => opt.selected);

return selectedOption ? getBoundValue(selectedOption) : input.value;
}

return input.value;
}
34 changes: 34 additions & 0 deletions packages/vee-validate/tests/Field.spec.ts
Expand Up @@ -1004,4 +1004,38 @@ describe('<Field />', () => {
await flushPromises();
expect((form as any).field).toBe('hello');
});

// #3440
test('should preserve select input options value type', async () => {
const value = ref();

const wrapper = mountWithHoc({
setup() {
return {
value,
};
},
template: `
<Field as="select" v-model="value" name="hello">
<option id="true" :value="true">Yes</option>
<option id="false" :value="false">No</option>
</Field>
`,
});

await flushPromises();
const select = document.querySelector('select') as HTMLSelectElement;
const optTrue = document.querySelector('#true') as HTMLOptionElement;
const optFalse = document.querySelector('#false') as HTMLOptionElement;

optTrue.selected = true;
dispatchEvent(select, 'change');
await flushPromises();
expect(value.value).toBe(true);

optFalse.selected = true;
dispatchEvent(select, 'change');
await flushPromises();
expect(value.value).toBe(false);
});
});
4 changes: 2 additions & 2 deletions packages/vee-validate/tests/helpers/index.ts
Expand Up @@ -41,9 +41,9 @@ export function setChecked(node: HTMLInputElement, status?: boolean) {
node.dispatchEvent(new window.Event('input'));
}

export function dispatchEvent(node: ComponentPublicInstance | HTMLInputElement, eventName: string) {
export function dispatchEvent(node: ComponentPublicInstance | HTMLElement, eventName: string) {
if (HTML_TAGS.includes((node as any).tagName)) {
const input = node as HTMLInputElement;
const input = node as HTMLElement;
input.dispatchEvent(new window.Event(eventName));
return;
}
Expand Down

0 comments on commit b144615

Please sign in to comment.