From 60ec7f768a956ed53606f8545ad19b1c19108f81 Mon Sep 17 00:00:00 2001 From: Waseem Dahman Date: Sun, 17 May 2020 00:09:45 -0400 Subject: [PATCH] Add ability to disable blur validation (#136) * add nullish coalescing support * add ability to disable on blur validation * fix redundant calls of blur validation --- .eslintrc | 4 + README.md | 6 +- package.json | 3 +- src/useFormState.js | 18 +- test/useFormState-validation.test.js | 11 + yarn.lock | 1157 +++++++++++++++----------- 6 files changed, 720 insertions(+), 479 deletions(-) diff --git a/.eslintrc b/.eslintrc index 0c7686d..c91a4ed 100644 --- a/.eslintrc +++ b/.eslintrc @@ -16,6 +16,10 @@ "no-underscore-dangle": ["error", { "allow": ["__DEV__"] }] }, "overrides": [ + { + "files": ["**/*.js"], + "parser": "babel-eslint" + }, { "files": ["test/**/*.js"], "rules": { diff --git a/README.md b/README.md index bbc5308..db33243 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ - [Labels](#labels) - [Custom Controls](#custom-controls) - [Updating Fields Manually](#updating-fields-manually) - - [Resetting The Formm State](#resetting-the-form-state) + - [Resetting The Form State](#resetting-the-form-state) - [Working with TypeScript](#working-with-typescript) - [API](#api) - [`initialState`](#initialstate) @@ -591,7 +591,7 @@ formState.reset(); // resetting the form state #### `formOptions.validateOnBlur` -When set to `true`, all form fields will validated when the input loses focus. If not specified, the `validate` function of each input will be called on value change. +By default, input validation is performed on both of the `change` and the `blur` events. Setting `validateOnBlur` to `true` will limit input validation to be **only** performed on `blur` (when the input loses focus). When set to `false`, input validation will **only** be performed on `change`. #### `formOptions.withIds` @@ -742,7 +742,7 @@ The following options can be passed: | `onBlur(e): void` | Optional. A blur event handler that's called with the input's `blur` [`SyntheticEvent`](https://reactjs.org/docs/events.html). | | `validate(value, values, e): any` | Optional (required for `raw` inputs). An input validation function that determines whether the input value is valid. It's called with the input value, all input values in the form, and the change/blur event (or the raw value of the control in the case of `.raw()`). The input is considered **valid** if this method returns `true` or `undefined`. Any [truthy value](https://developer.mozilla.org/en-US/docs/Glossary/Truthy) other than `true` returned from this method will make the input **invalid**. Such values are used a **custom validation errors** that can be retrieved from [`state.errors`](#form-state). HTML5 validation rules are ignored when this function is specified. | | `compare(initialValue, value): any` | Optional (required for `raw` inputs). A comparison function that determines whether the input value is pristine. It's called with the input's initial value, and the input's current value. It must return a boolean indicating whether the form is pristine. | -| `validateOnBlur: boolean` | Optional. `false` by default. When set to `true` and the `validate` function is provided, the function will be called when the input loses focus. If not specified, the `validate` function will be called on value change. | +| `validateOnBlur: boolean` | Optional. Unspecified by default. When unspecified, input validation is performed on both of the `change` and the `blur` events. Setting `validateOnBlur` to `true` will limit input validation to be **only** performed on `blur` (when the input loses focus). When set to `false`, input validation will **only** be performed on `change`. | | `touchOnChange: boolean` | Optional. `false` by default. When `false`, the input will be marked as touched when the `onBlur()` event handler is called. For custom controls that do not support `onBlur`, setting this to `true` will make it so inputs will be marked as touched when `onChange()` is called instead. | ## License diff --git a/package.json b/package.json index 922c54b..d2744e1 100644 --- a/package.json +++ b/package.json @@ -56,7 +56,7 @@ "@babel/cli": "^7.1.2", "@babel/core": "^7.1.2", "@babel/plugin-transform-runtime": "^7.3.4", - "@babel/preset-env": "^7.1.0", + "@babel/preset-env": "^7.9.6", "@babel/preset-react": "^7.0.0", "@rollup/plugin-babel": "^5.0.0", "@rollup/plugin-replace": "^2.3.2", @@ -64,6 +64,7 @@ "@types/react": "^16.8.4", "@wsmd/eslint-config": "^1.2.0", "babel-core": "^7.0.0-bridge.0", + "babel-eslint": "^10.1.0", "babel-jest": "^23.6.0", "coveralls": "^3.0.9", "eslint": "^6.8.0", diff --git a/src/useFormState.js b/src/useFormState.js index 26eb72e..0089242 100644 --- a/src/useFormState.js +++ b/src/useFormState.js @@ -36,7 +36,7 @@ export default function useFormState(initialState, options) { const formState = useState({ initialState }); const { getIdProp } = useInputId(formOptions.withIds); - const { set: setDirty, has: isDirty } = useCache(); + const { set: setDirty, get: isDirty } = useCache(); const callbacks = useCache(); const devWarnings = useCache(); @@ -141,6 +141,10 @@ export default function useFormState(initialState, options) { formState.comparators.set(name, getCompareFn()); + function getValidateOnBlur() { + return formOptions.validateOnBlur ?? inputOptions.validateOnBlur; + } + function validate( e, value = isRaw ? formState.current.values[name] : e.target.value, @@ -284,11 +288,7 @@ export default function useFormState(initialState, options) { formOptions.onChange(e, formState.current.values, newValues); - const validateOnBlur = formOptions.validateOnBlur - ? inputOptions.validateOnBlur !== false - : inputOptions.validateOnBlur; - - if (!validateOnBlur) { + if (!getValidateOnBlur()) { validate(e, value, newValues); } @@ -307,10 +307,12 @@ export default function useFormState(initialState, options) { * A) when it's either touched for the first time * B) when it's marked as dirty due to a value change */ - /* istanbul ignore else */ if (!formState.current.touched[name] || isDirty(name)) { - validate(e); setDirty(name, false); + // http://github.com/wsmd/react-use-form-state/issues/127#issuecomment-597989364 + if (getValidateOnBlur() ?? true) { + validate(e); + } } }), ...getIdProp('id', name, ownValue), diff --git a/test/useFormState-validation.test.js b/test/useFormState-validation.test.js index c62ce77..05afecd 100644 --- a/test/useFormState-validation.test.js +++ b/test/useFormState-validation.test.js @@ -58,6 +58,17 @@ describe('passing a custom input validate function', () => { ); }); + it('does not validate input on blur when validateOnBlur is false', () => { + const validate = jest.fn(() => false); + const { change, blur } = renderWithFormState(([, { text }]) => ( + + )); + change({ value: 'test' }); + expect(validate).toHaveBeenCalled(); + blur(); + expect(validate).toHaveBeenCalledTimes(1); + }); + it('marks input as valid', () => { const { change, formState } = renderWithFormState(([, { text }]) => (