Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(Forms): deprecate validator in favor of onChangeValidator #4314

Merged
merged 7 commits into from
Nov 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export const CreateBasicFieldComponent = () => {
const preparedProps = {
label: 'What is the secret of this field?',
fromInput,
validator: (value) => {
onChangeValidator: (value) => {
if (value === 'secret') {
return new Error('Do not reveal the secret!')
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ export const AsyncChangeAndValidation = () => {
label='Type "valid" to validate the field'
path="/myField"
required
validator={validator}
onChangeValidator={validator}
onChange={onChangeField}
autoComplete="off"
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ export const AsyncChangeBehavior = () => {
path="/myField1"
label="Label (with async validation)"
placeholder="Write something ..."
validator={delay}
onChangeValidator={delay}
/>
<FieldBlock width="medium">
<Field.String
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,6 @@ function ComponentB() {

**tl;dr:** the `useData` hook returns unvalidated data.

When you use an async `onChange` or `validator` event handler on a field, it will delay the "submitted" value, because of its async nature.
When you use an async `onChange`, `onChangeValidator` or `onBlurValidator` event handler on a field, it will delay the "submitted" value, because of its async nature.

That means, if you want to access the value of a field immediately, you can use the `useData` hook for that, as it always returns unvalidated data, in sync.
Original file line number Diff line number Diff line change
Expand Up @@ -443,7 +443,7 @@ export const InitialOpenWithToolbarVariant = () => {
<Iterate.Array
path="/countries"
defaultValue={[null]}
validator={(arrayValue) => {
onChangeValidator={(arrayValue) => {
const findFirstDuplication = (arr) =>
arr.findIndex((e, i) => arr.indexOf(e) !== i)

Expand Down Expand Up @@ -535,7 +535,7 @@ export const WithArrayValidator = () => {
<Card stack>
<Iterate.Array
path="/items"
validator={(arrayValue) => {
onChangeValidator={(arrayValue) => {
if (!(arrayValue && arrayValue.length > 1)) {
return new Error('You need at least two items')
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -178,13 +178,13 @@ export const AsyncWizardContainer = () => {
<Card stack>
<Field.String
label="Required field with async validator"
validator={validator1}
onChangeValidator={validator1}
path="/field1"
required
/>
<Field.String
label="Field with async validator"
validator={validator2}
onChangeValidator={validator2}
path="/field2"
/>
</Card>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -316,13 +316,13 @@ export const ValidatePattern = () => {
)
}

export const SynchronousExternalValidator = () => {
export const SynchronousExternalChangeValidator = () => {
return (
<ComponentBox>
<Field.String
defaultValue="foo"
label="Label text (minimum 4 characters)"
validator={(value) =>
onChangeValidator={(value) =>
value.length < 4 ? Error('At least 4 characters') : undefined
}
onChange={(value) => console.log('onChange', value)}
Expand All @@ -331,13 +331,13 @@ export const SynchronousExternalValidator = () => {
)
}

export const AsynchronousExternalValidator = () => {
export const AsynchronousExternalChangeValidator = () => {
return (
<ComponentBox>
<Field.String
defaultValue="foo"
label="Label text (minimum 4 characters)"
validator={(value) =>
onChangeValidator={(value) =>
new Promise((resolve) =>
setTimeout(
() =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,11 +74,11 @@ This example demonstrates how the status message width adjusts according to the

### Synchronous external validator (called on every change)

<Examples.SynchronousExternalValidator />
<Examples.SynchronousExternalChangeValidator />

### Asynchronous external validator (called on every change)

<Examples.AsynchronousExternalValidator />
<Examples.AsynchronousExternalChangeValidator />

### Synchronous external validator (called on blur)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,8 @@ All properties are optional and can be used as needed. These properties can be p

- `required` if true, it will call `validateRequired` for validation.
- `schema` or `pattern` for JSON schema validation powered by [ajv](https://ajv.js.org/).
- `validator` your custom validation function. It will run on every keystroke. Can be an async function. Use it together with [debounceAsync](/uilib/helpers/functions/#debounce).
- `onBlurValidator` your custom validation function. It will run on a `handleBlur()` call. Use it over `validator` for validations with side-effects. Can be an async function.
- `onChangeValidator` your custom validation function. It will run on every keystroke. Can be an async function. Use it together with [debounceAsync](/uilib/helpers/functions/#debounce).
- `onBlurValidator` your custom validation function. It will run on a `handleBlur()` call. Use it over `onChangeValidator` for validations with side-effects. Can be an async function.
- `validateRequired` does allow you to provide a custom logic for how the `required` property should validate. See example down below.
- `validateInitially` in order to show an error without a change and blur event. Used for rare cases.
- `validateUnchanged` in order to validate without a change and blur event. Used for rare cases.
Expand Down Expand Up @@ -166,7 +166,8 @@ During validation, the different APIs do have a prioritization order and will st

1. `required` property
1. `schema` property (including `pattern`)
1. `validator` property
1. `onChangeValidator` property
1. `onBlurValidator` property

### Error handling

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,5 @@ There is a corresponding [Value.BankAccountNumber](/uilib/extensions/forms/Value

### Internal validators exposed

`Field.BankAccountNumber` expose the `bankAccountNumberValidator` validator through its `validator` and `onBlurValidator` property, take a look at [this demo](/uilib/extensions/forms/feature-fields/BankAccountNumber/demos/#extend-validation-with-custom-validation-function).
`Field.BankAccountNumber` expose the `bankAccountNumberValidator` validator through its `onChangeValidator` and `onBlurValidator` property, take a look at [this demo](/uilib/extensions/forms/feature-fields/BankAccountNumber/demos/#extend-validation-with-custom-validation-function).
The `bankAccountNumberValidator` validator, validates if the bank account number provided is a [Norwegian bank account number](https://no.wikipedia.org/wiki/Kontonummer) or not.
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ Below is an example of the error message displayed when there's an invalid D num

### Validation function

You can provide your own validation function, either to `validator` or `onBlurValidator`.
You can provide your own validation function, either to `onChangeValidator` or `onBlurValidator`.

<Examples.ValidationFunction />

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ There is a corresponding [Value.NationalIdentityNumber](/uilib/extensions/forms/

### Internal validators exposed

`Field.NationalIdentityNumber` expose the following validators through its `validator` and `onBlurValidator` property:
`Field.NationalIdentityNumber` expose the following validators through its `onChangeValidator` and `onBlurValidator` property:

- `dnrValidator`: validates a D number.
- `fnrValidator`: validates a national identity number (fødselsnummer).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,5 @@ There is a corresponding [Value.OrganizationNumber](/uilib/extensions/forms/Valu

### Internal validators exposed

`Field.OrganizationNumber` expose the `organizationNumberValidator` validator through its `validator` and `onBlurValidator` property, take a look at [this demo](/uilib/extensions/forms/feature-fields/OrganizationNumber/demos/#extend-validation-with-custom-validation-function).
`Field.OrganizationNumber` expose the `organizationNumberValidator` validator through its `onChangeValidator` and `onBlurValidator` property, take a look at [this demo](/uilib/extensions/forms/feature-fields/OrganizationNumber/demos/#extend-validation-with-custom-validation-function).
The `organizationNumberValidator` validator, validates if the organization number provided is a [Norwegian organization number](https://www.brreg.no/om-oss/registrene-vare/om-enhetsregisteret/organisasjonsnummeret/) or not.
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ Countries are sorted in alphabetically order, with the following prioritized cou

## Validation

By default it has no validation. But you can enable it by giving a `required`, `pattern`, `schema` or `validator` property with the needed validation. More about validation in the [Getting Started](/uilib/extensions/forms/getting-started/#validation) section.
By default it has no validation. But you can enable it by giving a `required`, `pattern`, `schema`, `onChangeValidator` or `onBlurValidator` property with the needed validation. More about validation in the [Getting Started](/uilib/extensions/forms/getting-started/#validation) section.

### Norwegian mobile numbers

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,4 @@ render(<Field.Password />)

## Validation

By default it has no validation. But you can enable it by giving a `required`, `pattern`, `schema` or `validator` property with the needed validation. More about validation in the [Getting Started](/uilib/extensions/forms/getting-started/#validation) section.
By default it has no validation. But you can enable it by giving a `required`, `pattern`, `schema`, `onChangeValidator` or `onBlurValidator` property with the needed validation. More about validation in the [Getting Started](/uilib/extensions/forms/getting-started/#validation) section.
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ import AsyncChangeExample from './Form/Handler/parts/async-change-example.mdx'
- [required](#required)
- [pattern](#pattern)
- [schema](#schema)
- [onBlurValidator and validator](#onblurvalidator-and-validator)
- [onBlurValidator and onChangeValidator](#onblurvalidator-and-onchangevalidator)
- [Connect with another field](#connect-with-another-field)
- [Async validation](#async-validation)
- [Async validator with debounce](#async-validator-with-debounce)
Expand Down Expand Up @@ -390,13 +390,13 @@ More info about the async change behavior in the form [Handler](/uilib/extension

#### Async field validation

A similar indicator behavior will occur when using async functions for field validation, such as `validator` or `onBlurValidation`, your form will exhibit async behavior. This means that the validation needs to be successfully completed before the form can be submitted.
A similar indicator behavior will occur when using async functions for field validation, such as `onChangeValidator` or `onBlurValidation`, your form will exhibit async behavior. This means that the validation needs to be successfully completed before the form can be submitted.

### Validation and error handling

Every field component has a built-in validation that is based on the type of data it handles. This validation is automatically applied to the field when the user interacts with it. The validation is also applied when the user submits the form.

In addition, you can add your own validation to a field component. This is done by adding a `required`, `pattern`, `schema` or `validator` property.
In addition, you can add your own validation to a field component. This is done by adding a `required`, `pattern`, `schema`, `onChangeValidator` or `onBlurValidation` property.

Fields which have the `disabled` property or the `readOnly` property, will skip validation.

Expand Down Expand Up @@ -487,9 +487,9 @@ const schema = {
<Field.PhoneNumber schema={schema} />
```

#### onBlurValidator and validator
#### onBlurValidator and onChangeValidator

The `onBlurValidator` and `validator` properties accepts a function that takes the current value of the field as an argument and returns an error message if the value is invalid:
The `onBlurValidator` and `onChangeValidator` properties accepts a function that takes the current value of the field as an argument and returns an error message if the value is invalid:

```tsx
const onChangeValidator = (value) => {
Expand All @@ -498,14 +498,14 @@ const onChangeValidator = (value) => {
return new Error('Invalid value message')
}
}
render(<Field.PhoneNumber validator={onChangeValidator} />)
render(<Field.PhoneNumber onChangeValidator={onChangeValidator} />)
```

You can find more info about error messages in the [error messages](/uilib/extensions/forms/Form/error-messages/) docs.

##### Connect with another field

You can also use the `connectWithPath` function to connect the validator to another field. This allows you to rerun the validator function once the value of the connected field changes:
You can also use the `connectWithPath` function to connect the validator (`onChangeValidator` and `onBlurValidator`) to another field. This allows you to rerun the validator function once the value of the connected field changes:

```tsx
import { Form, Field } from '@dnb/eufemia/extensions/forms'
Expand All @@ -523,15 +523,15 @@ render(
<Field.Number path="/myReference" defaultValue={2} />

<Field.Number
path="/withValidator"
path="/withOnChangeValidator"
defaultValue={2}
validator={onChangeValidator} // NB: You may use "onBlurValidator" depending on use case.
onChangeValidator={onChangeValidator} // NB: You may use "onBlurValidator" depending on use case.
/>
</Form.Handler>,
)
```

By default, the validator function will only run when the "/withValidator" field is changed. When the error message is shown, it will update the message with the new value of the "/myReference" field.
By default, the `onChangeValidator` function will only run when the "/withOnChangeValidator" field is changed. When the error message is shown, it will update the message with the new value of the "/myReference" field.

You can also change this behavior for testing purposes by using the following properties:

Expand Down Expand Up @@ -576,7 +576,7 @@ const onChangeValidator = debounceAsync(async function myValidator(value) {
return error
}
})
render(<Field.PhoneNumber validator={onChangeValidator} />)
render(<Field.PhoneNumber onChangeValidator={onChangeValidator} />)
```

### Localization and translation
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -603,7 +603,10 @@ export default function Provider<Data extends JsonObject>(
for (const path in fieldPropsRef.current) {
if (mountedFieldsRef.current[path]?.isMounted) {
const props = fieldPropsRef.current[path]
if (isAsync(props.validator) || isAsync(props.onBlurValidator)) {
if (
isAsync(props.onChangeValidator) ||
isAsync(props.onBlurValidator)
) {
return true
}
}
Expand Down
Loading
Loading