Skip to content

Commit

Permalink
feat(Forms): deprecate Form.useError in favor of Form.useValidation
Browse files Browse the repository at this point in the history
… featuring `setFieldStatus` to handle the status (error) of a single field (#3986)
  • Loading branch information
tujoworker authored Sep 25, 2024
1 parent 0c121f1 commit dd39eef
Show file tree
Hide file tree
Showing 19 changed files with 843 additions and 394 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,10 @@ The `InputPassword` component has been moved to `Field.Password`, and is now a p

- replace `withValue` with `hasValue`.

## Form.useError

- replace `useError` with `useValidation`.

## Form.Iterate

- Rename label variable `{itemNr}` to `{itemNo}`.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -371,7 +371,7 @@ export const FilterData = () => {

const Output = () => {
const { filterData } = Form.useData(id)
const { hasErrors } = Form.useError(id)
const { hasErrors } = Form.useValidation(id)

return (
<Section
Expand Down

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
---
title: 'useValidation'
description: '`Form.useValidation` lets you monitor and modify field status or your form errors outside of the context.'
hideInMenu: true
showTabs: true
tabs:
- title: Info
key: '/info'
- title: Demos
key: '/demos'
breadcrumb:
- text: Forms
href: /uilib/extensions/forms/
- text: Form
href: /uilib/extensions/forms/Form/
- text: Form.useValidation
href: /uilib/extensions/forms/Form/useValidation/
redirect_from:
- /uilib/extensions/forms/Form/useError
---

import Info from 'Docs/uilib/extensions/forms/Form/useValidation/info'
import Demos from 'Docs/uilib/extensions/forms/Form/useValidation/demos'

<Info />
<Demos />
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ export function HasErrors() {
showError: true,
isVisible: true,
})
const { hasErrors, hasFieldError } = Form.useError('default-id')
const { hasErrors, hasFieldError } =
Form.useValidation('default-id')

return (
<Form.Handler id="default-id">
Expand Down Expand Up @@ -61,3 +62,46 @@ export function HasErrors() {
</ComponentBox>
)
}

export function SetFieldStatus() {
return (
<ComponentBox>
{() => {
const MyForm = () => {
const { setFieldStatus } = Form.useValidation('form-status')

return (
<Form.Handler
id="form-status"
onSubmit={async () => {
await new Promise((resolve) => setTimeout(resolve, 1000))

setFieldStatus('/myField', {
error: new Error('This is a field error'),
warning: 'This is a field warning',
info: 'This is a field info',
})

await new Promise((resolve) => setTimeout(resolve, 5000))

setFieldStatus('/myField', {
error: null,
warning: null,
info: null,
})
}}
>
<Flex.Stack>
<Field.String label="My field" path="/myField" />

<Form.SubmitButton />
</Flex.Stack>
</Form.Handler>
)
}

return <MyForm />
}}
</ComponentBox>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ import * as Examples from './Examples'

## Demos

### Set field status

<Examples.SetFieldStatus />

### Check for errors with hasErrors

<Examples.HasErrors />
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
---
showTabs: true
---

## Description

The `Form.useValidation` lets you monitor and modify field status or your form errors outside of the context.

## Usage

You can use it in several ways. Like within the context of `Form.Handler`:

```jsx
import { Form } from '@dnb/eufemia/extensions/forms'

function MyForm() {
return (
<Form.Handler>
...
<Component />
...
</Form.Handler>
)
}

function Component() {
const { hasErrors, hasFieldError, setFormError, setFieldStatus } =
Form.useValidation()

// True if any error is present
hasErrors()

// True if the field has an error
hasFieldError('/path/to/field')

// Report a form error
setFormError(new Error('This is a global form error'))

// Show a field error
setFieldStatus('/path/to/field', {
error: new Error('This is a field error'),
warning: 'This is a field warning',
info: 'This is a field info',
})
}
```

Or by linking the hook together with the form by using the `id` (string) property:

```jsx
import { Form } from '@dnb/eufemia/extensions/forms'

function MyForm() {
return (
<>
<Form.Handler id="unique">...</Form.Handler>
<Component />
</>
)
}

function Component() {
const { hasErrors, hasFieldError } = Form.useValidation('unique')
}
```

Or by using it in the form component itself:

```jsx
import { Form } from '@dnb/eufemia/extensions/forms'

function MyForm() {
const { hasErrors } = Form.useValidation('unique')

return <Form.Handler id="unique">...</Form.Handler>
}
```

## Report a form error

You can also report a form error that gets displayed on the bottom of the form by using the `Form.useValidation` hook:

```jsx
import { Form } from '@dnb/eufemia/extensions/forms'

function MyForm() {
const { setFormError } = Form.useValidation('unique')

useEffect(() => {
setFormError('This is a global form error')
}, [])

return <Form.Handler id="unique">...</Form.Handler>
}
```

## Field status

You can also use the `setFieldStatus` method to report field status. This will update the field with the status and show it in the form.

```jsx
import { Form, Field } from '@dnb/eufemia/extensions/forms'

function Component() {
const { setFieldStatus } = Form.useValidation('unique')

return (
<Form.Handler
id="unique"
onSubmit={async () => {
// Report a field status
setFieldStatus('/path/to/field', {
error: new Error('This is a field error'),
warning: 'This is a field warning',
info: 'This is a field info',
})
}}
>
<Field.String path="/path/to/field" />
</Form.Handler>
)
}
```

To remove the field status, you can use `setFieldStatus('/path/to/field', { error: null })`.

## Accessibility

The form error is connected with the [Form.Handler](/uilib/extensions/forms/Form/Handler/) itself via `aria-labelledby` for screen reader support.
Original file line number Diff line number Diff line change
Expand Up @@ -359,7 +359,7 @@ In addition, you can add your own validation to a field component. This is done

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

For monitoring and set your form errors, you can use the [useError](/uilib/extensions/forms/Form/useError) hook.
For monitoring and setting your form errors, you can use the [useValidation](/uilib/extensions/forms/Form/useValidation) hook.

#### Summary for errors

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,9 @@ export type HandleSubmitCallback = ({
}: {
preventSubmit: () => void
}) => void
export type FieldConnections = {
setEventResult?: (status: EventStateObject) => void
}

export interface ContextState {
id?: Identifier
Expand Down Expand Up @@ -141,8 +144,10 @@ export interface ContextState {
setFieldProps?: (path: Path, props: unknown) => void
setValueProps?: (path: Path, props: unknown) => void
setHandleSubmit?: (callback: HandleSubmitCallback) => void
setFieldConnection?: (path: Path, connections: FieldConnections) => void
fieldPropsRef?: React.MutableRefObject<Record<string, FieldProps>>
valuePropsRef?: React.MutableRefObject<Record<string, ValueProps>>
fieldConnectionsRef?: React.RefObject<Record<Path, FieldConnections>>
mountedFieldsRef?: React.MutableRefObject<Record<Path, MountState>>
showAllErrors: boolean
hasVisibleError: boolean
Expand Down
Loading

0 comments on commit dd39eef

Please sign in to comment.