Skip to content

Commit

Permalink
feat: deprecate the disabled prop
Browse files Browse the repository at this point in the history
  • Loading branch information
logaretm committed Oct 26, 2020
1 parent c95a665 commit 29f4dca
Show file tree
Hide file tree
Showing 8 changed files with 19 additions and 115 deletions.
23 changes: 0 additions & 23 deletions docs/content/api/field.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,6 @@ When using `v-slot` on the `Field` component you no longer have to provide an `a
| rules | `object \| string \| Function` | `null` | The field's validation rules |
| validateOnMount | `boolean` | `false` | If true, field will be validated when the component is mounted |
| bails | `boolean` | `true` | Stops validating as soon as a rule fails the validation |
| disabled | `disabled` | `false` | Disables validation and the field will no longer participate in the parent form state |
| label | `string` | `undefined` | A different string to override the field `name` prop in error messages, useful for display better or formatted names |

### Slots
Expand Down Expand Up @@ -134,20 +133,6 @@ The first error in the `errors` array if available, a handy shortcut to display

<code-title level="4">

`disabled: boolean`

</code-title>

A reactive reference to the field's current disabled state, this allows/prevents the field from participating in it's owning form's validation state and doesn't block the submission handlers even if invalid.

```js
const { disabled } = useField('field', value => !!value);

disabled.value; // true or false
```

<code-title level="4">

`reset: () => void`

</code-title>
Expand Down Expand Up @@ -238,14 +223,6 @@ The field's current value, you can bind it with `value` prop on your inputs to s

<code-title level="5">

`field.disabled: boolean`

</code-title>

The field's current disabled state, this allows/prevents the field from participating in it's owning form's validation state and doesn't block the submission handlers even if invalid.

<code-title level="5">

`field.name: string`

</code-title>
Expand Down
2 changes: 1 addition & 1 deletion docs/content/api/form.md
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ interface FormMeta {

</code-title>

Contains the current form values, it will only contain the active (non-disabled) fields.
Contains the current form values

<code-title level="4">

Expand Down
16 changes: 0 additions & 16 deletions docs/content/api/use-field.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,6 @@ The full signature of the `useField` function looks like this:
```typescript
interface FieldOptions {
initialValue?: any; // the initial value, cannot be a ref
disabled?: MaybeReactive<boolean>; // if the input is disabled, can be a ref
validateOnMount?: boolean; // if the field should be validated when the component is mounted
validateOnValueUpdate?: boolean; // if the field should be validated when the value changes (default is true)
bails?: boolean; // if the field validation should run all validations
Expand All @@ -86,7 +85,6 @@ type useField = (
meta: FieldMeta;
errors: Ref<string[]>; // all error messages
errorMessage: Ref<string | undefined>; // the first error message
disabled: Ref<boolean>; // if the field is currently disabled
reset: () => void; // resets errors and field meta
validate: () => Promise<ValidationResult>; // validates and updates the errors and field meta
handleChange: (e: Event) => void; // updates the value
Expand Down Expand Up @@ -214,20 +212,6 @@ errorMessage.value; // 'field is not valid' or undefined

<code-title level="4">

`disabled: Ref<boolean>`

</code-title>

A reactive reference to the field's current disabled state, this allows/prevents the field from participating in it's owning form's validation state and doesn't block the submission handlers even if invalid.

```js
const { disabled } = useField('field', value => !!value);

disabled.value; // true or false
```

<code-title level="4">

`reset: () => void`

</code-title>
Expand Down
4 changes: 2 additions & 2 deletions docs/content/api/use-form.md
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ meta.value; // { valid: false, invalid: true, dirty: true, .... }

</code-title>

A computed property that contains the current form values, it will only contain the active (non-disabled) fields.
A computed property that contains the current form values

```js
const { values } = useForm();
Expand Down Expand Up @@ -316,7 +316,7 @@ This is a higher order function used to create `submit` event handlers, You shou

The handlers created using this function will automatically prevent form submission and stop the propagation of the submit event.

It accepts a function which runs after validating the form and if all fields are valid. The callback you pass will receive the form values as the first argument, which is an object containing the active (non-disabled) fields' values.
It accepts a function which runs after validating the form and if all fields are valid. The callback you pass will receive the form values as the first argument, which is an object containing the fields' values.

```vue
<template>
Expand Down
8 changes: 1 addition & 7 deletions packages/core/src/Field.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,17 +27,13 @@ export const Field = defineComponent({
type: Boolean,
default: () => getConfig().bails,
},
disabled: {
type: Boolean,
default: false,
},
label: {
type: String,
default: undefined,
},
},
setup(props, ctx) {
const [disabled, rules] = [toRef(props, 'disabled'), toRef(props, 'rules')];
const rules = toRef(props, 'rules');

const {
errors,
Expand All @@ -55,7 +51,6 @@ export const Field = defineComponent({
} = useField(props.name, rules, {
validateOnMount: props.validateOnMount,
bails: props.bails,
disabled,
type: ctx.attrs.type as string,
// Gets the initial value either from `value` prop/attr or `v-model` binding (modelValue)
// For checkboxes and radio buttons it will always be the model value not the `value` attribute
Expand Down Expand Up @@ -100,7 +95,6 @@ export const Field = defineComponent({
const makeSlotProps = () => {
const fieldProps: Record<string, any> = {
name: props.name,
disabled: props.disabled,
onBlur: [handleBlur],
onInput: [onInputHandler, valueTick],
onChange: [onInputHandler, valueTick],
Expand Down
17 changes: 4 additions & 13 deletions packages/core/src/useField.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ import { FormInitialValues, FormSymbol } from './symbols';

interface FieldOptions {
initialValue: any;
disabled: MaybeReactive<boolean>;
validateOnValueUpdate: boolean;
validateOnMount?: boolean;
bails?: boolean;
Expand All @@ -44,16 +43,10 @@ type RuleExpression = MaybeReactive<string | Record<string, any> | GenericValida
* Creates a field composite.
*/
export function useField(name: string, rules: RuleExpression, opts?: Partial<FieldOptions>) {
const {
initialValue,
validateOnMount,
bails,
disabled,
type,
valueProp,
label,
validateOnValueUpdate,
} = normalizeOptions(name, opts);
const { initialValue, validateOnMount, bails, type, valueProp, label, validateOnValueUpdate } = normalizeOptions(
name,
opts
);

const form = injectWithSelf(FormSymbol);
const { meta, errors, handleBlur, handleInput, reset, setValidationState, value, checked } = useValidationState({
Expand Down Expand Up @@ -123,7 +116,6 @@ export function useField(name: string, rules: RuleExpression, opts?: Partial<Fie
meta,
errors,
errorMessage,
disabled,
type,
valueProp,
checked,
Expand Down Expand Up @@ -207,7 +199,6 @@ function normalizeOptions(name: string, opts: Partial<FieldOptions> | undefined)
validateOnMount: false,
bails: true,
rules: '',
disabled: false,
label: name,
validateOnValueUpdate: true,
});
Expand Down
28 changes: 11 additions & 17 deletions packages/core/src/useForm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,17 +55,12 @@ export function useForm<TValues extends Record<string, any> = Record<string, any
}, {} as Record<string, any>);
});

// a flat array of the non-disabled
const activeFields = computed(() => {
return fields.value.filter(field => !unref(field.disabled));
});

// a private ref for all form values
const formValues = reactive({}) as TValues;

// an aggregation of field errors in a map object
const errors = computed<{ [P in keyof TValues]?: string }>(() => {
return activeFields.value.reduce((acc: Record<keyof TValues, string>, field) => {
return fields.value.reduce((acc: Record<keyof TValues, string>, field) => {
// Check if its a grouped field (checkbox/radio)
let message: string | undefined;
if (Array.isArray(fieldsById.value[field.name])) {
Expand All @@ -83,15 +78,6 @@ export function useForm<TValues extends Record<string, any> = Record<string, any
}, {});
});

// same as form values but filtered disabled fields out
const activeFormValues = computed<TValues>(() => {
return activeFields.value.reduce((formData: Record<keyof TValues, any>, field) => {
setInPath(formData, field.name, unref(field.value));

return formData;
}, {});
});

// initial form values
const { initialValues } = useFormInitialValues<TValues>(fieldsById, formValues, opts?.initialValues);

Expand Down Expand Up @@ -289,14 +275,22 @@ export function useForm<TValues extends Record<string, any> = Record<string, any
}

const results = await Promise.all(
activeFields.value.map((f: any) => {
fields.value.map((f: any) => {
return f.validate();
})
);

return results.every(r => !r.errors.length);
};

const immutableFormValues = computed<TValues>(() => {
return fields.value.reduce((formData: Record<keyof TValues, any>, field) => {
setInPath(formData, field.name, unref(field.value));

return formData;
}, {});
});

const handleSubmit = (fn?: SubmissionHandler<TValues>) => {
return function submissionHandler(e: unknown) {
if (e instanceof Event) {
Expand All @@ -308,7 +302,7 @@ export function useForm<TValues extends Record<string, any> = Record<string, any
return validate()
.then(result => {
if (result && typeof fn === 'function') {
return fn(activeFormValues.value, { evt: e as SubmitEvent, form: formCtx });
return fn(immutableFormValues.value, { evt: e as SubmitEvent, form: formCtx });
}
})
.then(
Expand Down
36 changes: 0 additions & 36 deletions packages/core/tests/Form.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,42 +125,6 @@ describe('<Form />', () => {
expect(isReset).toBe(true);
});

test('disabled fields do not participate in validation', async () => {
let isInObject = false;
const wrapper = mountWithHoc({
setup() {
return {
disabled: false,
submit: (values: Record<string, any>) => {
isInObject = 'field' in values;
},
};
},
template: `
<VForm @submit="submit" as="form">
<Field rules="required" name="field" as="input" :disabled="disabled"/>
<button id="submit">Submit</button>
</VForm>
`,
});

const input = wrapper.$el.querySelector('input');
setValue(input, '123');
const button = wrapper.$el.querySelector('#submit');

button.click();
await flushPromises();

expect(isInObject).toBe(true);

(wrapper as any).disabled = true;
button.click();
await flushPromises();

expect(isInObject).toBe(false);
});

test('initial values can be set with initialValues prop', async () => {
const initialValues = {
field: 'hello',
Expand Down

0 comments on commit 29f4dca

Please sign in to comment.