Skip to content

Commit 0663539

Browse files
authored
fix: added a symbol to detect non passed props with Vue 3.1.x (#3295)
1 parent b778970 commit 0663539

3 files changed

Lines changed: 35 additions & 24 deletions

File tree

packages/vee-validate/src/Field.ts

Lines changed: 28 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import { h, defineComponent, toRef, SetupContext, resolveDynamicComponent, computed, watch } from 'vue';
22
import { getConfig } from './config';
33
import { useField } from './useField';
4-
import { normalizeChildren, hasCheckedAttr, shouldHaveValueBinding } from './utils';
4+
import { normalizeChildren, hasCheckedAttr, shouldHaveValueBinding, isPropPresent } from './utils';
55
import { toNumber } from '../../shared';
6+
import { EMPTY_VALUE } from './symbols';
67

78
interface ValidationTriggersProps {
89
validateOnMount: boolean;
@@ -62,6 +63,7 @@ export const Field = defineComponent({
6263
},
6364
modelValue: {
6465
type: null,
66+
default: EMPTY_VALUE,
6567
},
6668
modelModifiers: {
6769
type: null,
@@ -93,13 +95,7 @@ export const Field = defineComponent({
9395
validateOnMount: props.validateOnMount,
9496
bails: props.bails,
9597
type: ctx.attrs.type as string,
96-
// Gets the initial value either from `value` prop/attr or `v-model` binding (modelValue)
97-
// For checkboxes and radio buttons it will always be the model value not the `value` attribute
98-
initialValue: hasCheckedAttr(ctx.attrs.type)
99-
? props.modelValue
100-
: 'modelValue' in props
101-
? props.modelValue
102-
: ctx.attrs.value,
98+
initialValue: resolveInitialValue(props, ctx),
10399
// Only for checkboxes and radio buttons
104100
valueProp: ctx.attrs.value,
105101
uncheckedValue,
@@ -108,21 +104,19 @@ export const Field = defineComponent({
108104
});
109105

110106
// If there is a v-model applied on the component we need to emit the `update:modelValue` whenever the value binding changes
111-
const onChangeHandler =
112-
'modelValue' in props
113-
? function handleChangeWithModel(e: any) {
114-
handleChange(e);
115-
ctx.emit('update:modelValue', value.value);
116-
}
117-
: handleChange;
118-
119-
const onInputHandler =
120-
'modelValue' in props
121-
? function handleChangeWithModel(e: any) {
122-
handleInput(e);
123-
ctx.emit('update:modelValue', value.value);
124-
}
125-
: handleInput;
107+
const onChangeHandler = isPropPresent(props, 'modelValue')
108+
? function handleChangeWithModel(e: any) {
109+
handleChange(e);
110+
ctx.emit('update:modelValue', value.value);
111+
}
112+
: handleChange;
113+
114+
const onInputHandler = isPropPresent(props, 'modelValue')
115+
? function handleChangeWithModel(e: any) {
116+
handleInput(e);
117+
ctx.emit('update:modelValue', value.value);
118+
}
119+
: handleInput;
126120

127121
const fieldProps = computed(() => {
128122
const { validateOnInput, validateOnChange, validateOnBlur, validateOnModelUpdate } = resolveValidationTriggers(
@@ -161,7 +155,7 @@ export const Field = defineComponent({
161155
return attrs;
162156
});
163157

164-
if ('modelValue' in props) {
158+
if (isPropPresent(props, 'modelValue')) {
165159
const modelValue = toRef(props, 'modelValue');
166160
watch(modelValue, newModelValue => {
167161
if (newModelValue !== applyModifiers(value.value, props.modelModifiers)) {
@@ -237,3 +231,13 @@ function applyModifiers(value: unknown, modifiers: Record<string, boolean>) {
237231

238232
return value;
239233
}
234+
235+
function resolveInitialValue(props: Record<string, unknown>, ctx: SetupContext<any>) {
236+
// Gets the initial value either from `value` prop/attr or `v-model` binding (modelValue)
237+
// For checkboxes and radio buttons it will always be the model value not the `value` attribute
238+
if (!hasCheckedAttr(ctx.attrs.type)) {
239+
return isPropPresent(props, 'modelValue') ? props.modelValue : ctx.attrs.value;
240+
}
241+
242+
return isPropPresent(props, 'modelValue') ? props.modelValue : undefined;
243+
}

packages/vee-validate/src/symbols.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,5 @@ export const FormInitialValuesSymbol: InjectionKey<ComputedRef<Record<string, un
1212
);
1313

1414
export const FieldContextSymbol: InjectionKey<PrivateFieldComposite<unknown>> = Symbol('vee-validate-field-instance');
15+
16+
export const EMPTY_VALUE = Symbol('Default empty value');

packages/vee-validate/src/utils/assertions.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { Locator, YupValidator } from '../types';
22
import { isCallable, isObject } from '../../../shared';
3+
import { EMPTY_VALUE } from '../symbols';
34

45
export function isLocator(value: unknown): value is Locator {
56
return isCallable(value) && !!(value as Locator).__locatorRef;
@@ -99,3 +100,7 @@ export function isEvent(evt: unknown): evt is Event {
99100

100101
return false;
101102
}
103+
104+
export function isPropPresent(obj: Record<string, unknown>, prop: string) {
105+
return prop in obj && obj[prop] !== EMPTY_VALUE;
106+
}

0 commit comments

Comments
 (0)