Skip to content

Commit 60ec7f7

Browse files
authored
Add ability to disable blur validation (#136)
* add nullish coalescing support * add ability to disable on blur validation * fix redundant calls of blur validation
1 parent 5932047 commit 60ec7f7

6 files changed

Lines changed: 720 additions & 479 deletions

File tree

.eslintrc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@
1616
"no-underscore-dangle": ["error", { "allow": ["__DEV__"] }]
1717
},
1818
"overrides": [
19+
{
20+
"files": ["**/*.js"],
21+
"parser": "babel-eslint"
22+
},
1923
{
2024
"files": ["test/**/*.js"],
2125
"rules": {

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
- [Labels](#labels)
4040
- [Custom Controls](#custom-controls)
4141
- [Updating Fields Manually](#updating-fields-manually)
42-
- [Resetting The Formm State](#resetting-the-form-state)
42+
- [Resetting The Form State](#resetting-the-form-state)
4343
- [Working with TypeScript](#working-with-typescript)
4444
- [API](#api)
4545
- [`initialState`](#initialstate)
@@ -591,7 +591,7 @@ formState.reset(); // resetting the form state
591591

592592
#### `formOptions.validateOnBlur`
593593

594-
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.
594+
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`.
595595

596596
#### `formOptions.withIds`
597597

@@ -742,7 +742,7 @@ The following options can be passed:
742742
| `onBlur(e): void` | Optional. A blur event handler that's called with the input's `blur` [`SyntheticEvent`](https://reactjs.org/docs/events.html). |
743743
| `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. |
744744
| `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. |
745-
| `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. |
745+
| `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`. |
746746
| `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. |
747747

748748
## License

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,14 +56,15 @@
5656
"@babel/cli": "^7.1.2",
5757
"@babel/core": "^7.1.2",
5858
"@babel/plugin-transform-runtime": "^7.3.4",
59-
"@babel/preset-env": "^7.1.0",
59+
"@babel/preset-env": "^7.9.6",
6060
"@babel/preset-react": "^7.0.0",
6161
"@rollup/plugin-babel": "^5.0.0",
6262
"@rollup/plugin-replace": "^2.3.2",
6363
"@types/jest": "^24.0.11",
6464
"@types/react": "^16.8.4",
6565
"@wsmd/eslint-config": "^1.2.0",
6666
"babel-core": "^7.0.0-bridge.0",
67+
"babel-eslint": "^10.1.0",
6768
"babel-jest": "^23.6.0",
6869
"coveralls": "^3.0.9",
6970
"eslint": "^6.8.0",

src/useFormState.js

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ export default function useFormState(initialState, options) {
3636

3737
const formState = useState({ initialState });
3838
const { getIdProp } = useInputId(formOptions.withIds);
39-
const { set: setDirty, has: isDirty } = useCache();
39+
const { set: setDirty, get: isDirty } = useCache();
4040
const callbacks = useCache();
4141
const devWarnings = useCache();
4242

@@ -141,6 +141,10 @@ export default function useFormState(initialState, options) {
141141

142142
formState.comparators.set(name, getCompareFn());
143143

144+
function getValidateOnBlur() {
145+
return formOptions.validateOnBlur ?? inputOptions.validateOnBlur;
146+
}
147+
144148
function validate(
145149
e,
146150
value = isRaw ? formState.current.values[name] : e.target.value,
@@ -284,11 +288,7 @@ export default function useFormState(initialState, options) {
284288

285289
formOptions.onChange(e, formState.current.values, newValues);
286290

287-
const validateOnBlur = formOptions.validateOnBlur
288-
? inputOptions.validateOnBlur !== false
289-
: inputOptions.validateOnBlur;
290-
291-
if (!validateOnBlur) {
291+
if (!getValidateOnBlur()) {
292292
validate(e, value, newValues);
293293
}
294294

@@ -307,10 +307,12 @@ export default function useFormState(initialState, options) {
307307
* A) when it's either touched for the first time
308308
* B) when it's marked as dirty due to a value change
309309
*/
310-
/* istanbul ignore else */
311310
if (!formState.current.touched[name] || isDirty(name)) {
312-
validate(e);
313311
setDirty(name, false);
312+
// http://github.com/wsmd/react-use-form-state/issues/127#issuecomment-597989364
313+
if (getValidateOnBlur() ?? true) {
314+
validate(e);
315+
}
314316
}
315317
}),
316318
...getIdProp('id', name, ownValue),

test/useFormState-validation.test.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,17 @@ describe('passing a custom input validate function', () => {
5858
);
5959
});
6060

61+
it('does not validate input on blur when validateOnBlur is false', () => {
62+
const validate = jest.fn(() => false);
63+
const { change, blur } = renderWithFormState(([, { text }]) => (
64+
<input {...text({ name: 'name', validate, validateOnBlur: false })} />
65+
));
66+
change({ value: 'test' });
67+
expect(validate).toHaveBeenCalled();
68+
blur();
69+
expect(validate).toHaveBeenCalledTimes(1);
70+
});
71+
6172
it('marks input as valid', () => {
6273
const { change, formState } = renderWithFormState(([, { text }]) => (
6374
<input

0 commit comments

Comments
 (0)