From 6968cfd3889fe0d81427ce032c945e0006baa338 Mon Sep 17 00:00:00 2001 From: Harry Whorlow <79278353+harry-whorlow@users.noreply.github.com> Date: Mon, 25 Nov 2024 21:59:59 +0100 Subject: [PATCH] feat(core): add field listeners (#1032) * feat: add field listeners * feat: add onBlur listener * feat: add onSubmit listener * ci: apply automated fixes and generate docs * fix: stop onChange triggering onMount and add tests to assert this * feat: add listeners react documentation * fix: pull request comments * ci: apply automated fixes and generate docs * fix: pull request comments * feat: Vue docs * feat: Angular docs * feat: expose listeners on anguar wrapper and update docs * docs: fix react * docs: fix vue * ci: apply automated fixes and generate docs --------- Co-authored-by: ha1fstack <61955474+ha1fstack@users.noreply.github.com> Co-authored-by: Harry Whorlow Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: Leonardo Montini --- docs/config.json | 4 + .../angular/guides/basic-concepts.md | 35 +++++ docs/framework/angular/guides/listeners.md | 61 ++++++++ .../reference/classes/tanstackfield.md | 44 ++++-- docs/framework/react/guides/basic-concepts.md | 20 +++ docs/framework/react/guides/listeners.md | 67 ++++++++ docs/framework/vue/guides/basic-concepts.md | 29 ++++ docs/framework/vue/guides/listeners.md | 65 ++++++++ docs/reference/classes/fieldapi.md | 48 +++--- docs/reference/classes/formapi.md | 28 ++-- docs/reference/index.md | 1 + docs/reference/interfaces/fieldapioptions.md | 34 +++- docs/reference/interfaces/fieldlisteners.md | 66 ++++++++ docs/reference/interfaces/fieldoptions.md | 28 +++- docs/reference/interfaces/fieldvalidators.md | 22 +-- docs/reference/type-aliases/fieldmeta.md | 2 +- docs/reference/type-aliases/fieldstate.md | 2 +- .../src/tanstack-field.directive.ts | 5 + packages/form-core/src/FieldApi.ts | 85 ++++++++++ packages/form-core/src/FormApi.ts | 11 ++ packages/form-core/tests/FieldApi.spec.ts | 147 ++++++++++++++++++ packages/form-core/tests/FormApi.spec.ts | 24 +++ 22 files changed, 749 insertions(+), 79 deletions(-) create mode 100644 docs/framework/angular/guides/listeners.md create mode 100644 docs/framework/react/guides/listeners.md create mode 100644 docs/framework/vue/guides/listeners.md create mode 100644 docs/reference/interfaces/fieldlisteners.md diff --git a/docs/config.json b/docs/config.json index 6e5fdd20d..5a1589635 100644 --- a/docs/config.json +++ b/docs/config.json @@ -101,6 +101,10 @@ "label": "Linked Fields", "to": "framework/react/guides/linked-fields" }, + { + "label": "Listeners", + "to": "framework/react/guides/listeners" + }, { "label": "UI Libraries", "to": "framework/react/guides/ui-libraries" diff --git a/docs/framework/angular/guides/basic-concepts.md b/docs/framework/angular/guides/basic-concepts.md index 5e298359b..3f8860260 100644 --- a/docs/framework/angular/guides/basic-concepts.md +++ b/docs/framework/angular/guides/basic-concepts.md @@ -187,6 +187,41 @@ class AppComponent { } ``` +## Listeners + +`@tanstack/angular-form` allows you to react to specific triggers and "listen" to them to dispatch side effects. + +Example: + +```angular-ts +@Component({ + selector: 'app-root', + standalone: true, + imports: [TanStackField], + template: ` + + `, +}) + +... + +onCountryChange: FieldListenerFn = ({ + value, + }) => { + console.log(`Country changed to: ${value}, resetting province`) + this.form.setFieldValue('province', '') + } +``` + +More information can be found at [Listeners](./listeners.md) + ## Array Fields Array fields allow you to manage a list of values within a form, such as a list of hobbies. You can create an array field using the `tanstackField` directive. diff --git a/docs/framework/angular/guides/listeners.md b/docs/framework/angular/guides/listeners.md new file mode 100644 index 000000000..80a91b596 --- /dev/null +++ b/docs/framework/angular/guides/listeners.md @@ -0,0 +1,61 @@ +--- +id: listeners +title: Side effects for event triggers +--- + +For situations where you want to "affect" or "react" to triggers, there's the listener API. For example, if you, as the developer, want to reset a form field as a result of another field changing, you would use the listener API. + +Imagine the following user flow: + +- User selects a country from a drop-down. +- User then selects a province from another drop-down. +- User changes the selected country to a different one. + +In this example, when the user changes the country, the selected province needs to be reset as it's no longer valid. With the listener API, we can subscribe to the onChange event and dispatch a reset to the field "province" when the listener is fired. + +Events that can be "listened" to are: + +- onChange +- onBlur +- onMount +- onSubmit + +```angular-ts +@Component({ + selector: 'app-root', + standalone: true, + imports: [TanStackField], + template: ` + + + + `, +}) + +export class AppComponent { + form = injectForm({ + defaultValues: { + country: '', + province: '', + }, + }) + + onCountryChange: FieldListenerFn = ({ + value, + }) => { + console.log(`Country changed to: ${value}, resetting province`) + this.form.setFieldValue('province', '') + } +} +``` diff --git a/docs/framework/angular/reference/classes/tanstackfield.md b/docs/framework/angular/reference/classes/tanstackfield.md index fa74dc32a..3fe19007b 100644 --- a/docs/framework/angular/reference/classes/tanstackfield.md +++ b/docs/framework/angular/reference/classes/tanstackfield.md @@ -46,7 +46,7 @@ api: FieldApi; #### Defined in -[tanstack-field.directive.ts:58](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.directive.ts#L58) +[tanstack-field.directive.ts:62](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.directive.ts#L62) *** @@ -64,7 +64,7 @@ If `true`, always run async validation, even if there are errors emitted during #### Defined in -[tanstack-field.directive.ts:47](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.directive.ts#L47) +[tanstack-field.directive.ts:48](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.directive.ts#L48) *** @@ -82,7 +82,7 @@ The default time to debounce async validation if there is not a more specific de #### Defined in -[tanstack-field.directive.ts:46](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.directive.ts#L46) +[tanstack-field.directive.ts:47](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.directive.ts#L47) *** @@ -100,7 +100,7 @@ An optional object with default metadata for the field. #### Defined in -[tanstack-field.directive.ts:56](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.directive.ts#L56) +[tanstack-field.directive.ts:60](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.directive.ts#L60) *** @@ -118,7 +118,25 @@ An optional default value for the field. #### Defined in -[tanstack-field.directive.ts:45](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.directive.ts#L45) +[tanstack-field.directive.ts:46](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.directive.ts#L46) + +*** + +### listeners? + +```ts +optional listeners: NoInfer>; +``` + +A list of listeners which attach to the corresponding events + +#### Implementation of + +`FieldOptions.listeners` + +#### Defined in + +[tanstack-field.directive.ts:57](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.directive.ts#L57) *** @@ -136,7 +154,7 @@ The field name. The type will be `DeepKeys` to ensure your name is #### Defined in -[tanstack-field.directive.ts:41](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.directive.ts#L41) +[tanstack-field.directive.ts:42](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.directive.ts#L42) *** @@ -148,7 +166,7 @@ tanstackField: FormApi; #### Defined in -[tanstack-field.directive.ts:49](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.directive.ts#L49) +[tanstack-field.directive.ts:50](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.directive.ts#L50) *** @@ -164,7 +182,7 @@ optional unmount: () => void; #### Defined in -[tanstack-field.directive.ts:73](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.directive.ts#L73) +[tanstack-field.directive.ts:78](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.directive.ts#L78) *** @@ -182,7 +200,7 @@ A validator provided by an extension, like `yupValidator` from `@tanstack/yup-fo #### Defined in -[tanstack-field.directive.ts:48](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.directive.ts#L48) +[tanstack-field.directive.ts:49](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.directive.ts#L49) *** @@ -200,7 +218,7 @@ A list of validators to pass to the field #### Defined in -[tanstack-field.directive.ts:53](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.directive.ts#L53) +[tanstack-field.directive.ts:54](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.directive.ts#L54) ## Methods @@ -225,7 +243,7 @@ children are checked. #### Defined in -[tanstack-field.directive.ts:85](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.directive.ts#L85) +[tanstack-field.directive.ts:90](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.directive.ts#L90) *** @@ -248,7 +266,7 @@ before a directive, pipe, or service instance is destroyed. #### Defined in -[tanstack-field.directive.ts:81](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.directive.ts#L81) +[tanstack-field.directive.ts:86](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.directive.ts#L86) *** @@ -274,4 +292,4 @@ It is invoked only once when the directive is instantiated. #### Defined in -[tanstack-field.directive.ts:75](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.directive.ts#L75) +[tanstack-field.directive.ts:80](https://github.com/TanStack/form/blob/main/packages/angular-form/src/tanstack-field.directive.ts#L80) diff --git a/docs/framework/react/guides/basic-concepts.md b/docs/framework/react/guides/basic-concepts.md index 51045f253..30da761a8 100644 --- a/docs/framework/react/guides/basic-concepts.md +++ b/docs/framework/react/guides/basic-concepts.md @@ -195,6 +195,26 @@ const firstName = form.useStore((state) => state.values.firstName) Note: The usage of the `form.useField` hook to achieve reactivity is discouraged since it is designed to be used thoughtfully within the `form.Field` component. You might want to use `form.useStore` instead. +## Listeners + +`@tanstack/react-form` allows you to react to specific triggers and "listen" to them to dispatch side effects. + +Example: + +```tsx + { + console.log(`Country changed to: ${value}, resetting province`) + form.setFieldValue('province', '') + } + }} +/> +``` + +More information can be found at [Listeners](./listeners.md) + ## Array Fields Array fields allow you to manage a list of values within a form, such as a list of hobbies. You can create an array field using the `form.Field` component with the `mode="array"` prop. diff --git a/docs/framework/react/guides/listeners.md b/docs/framework/react/guides/listeners.md new file mode 100644 index 000000000..e794892d3 --- /dev/null +++ b/docs/framework/react/guides/listeners.md @@ -0,0 +1,67 @@ +--- +id: listeners +title: Side effects for event triggers +--- + +For situations where you want to "affect" or "react" to triggers, there's the listener API. For example, if you, as the developer, want to reset a form field as a result of another field changing, you would use the listener API. + +Imagine the following user flow: + +- User selects a country from a drop-down. +- User then selects a province from another drop-down. +- User changes the selected country to a different one. + +In this example, when the user changes the country, the selected province needs to be reset as it's no longer valid. With the listener API, we can subscribe to the onChange event and dispatch a reset to the field "province" when the listener is fired. + +Events that can be "listened" to are: + +- onChange +- onBlur +- onMount +- onSubmit + +```tsx +function App() { + const form = useForm({ + defaultValues: { + country: '', + province: '', + }, + // ... + }) + + return ( +
+ + {(field) => ( + + )} + + + + {(field) => ( + + )} + +
+ ) +} +``` diff --git a/docs/framework/vue/guides/basic-concepts.md b/docs/framework/vue/guides/basic-concepts.md index 79e07f06b..f4c470e1f 100644 --- a/docs/framework/vue/guides/basic-concepts.md +++ b/docs/framework/vue/guides/basic-concepts.md @@ -228,6 +228,35 @@ const firstName = form.useStore((state) => state.values.firstName) ``` +## Listeners + +`@tanstack/vue-form` allows you to react to specific triggers and "listen" to them to dispatch side effects. + +Example: + +```vue + +``` + +More information can be found at [Listeners](./listeners.md) + Note: The usage of the `form.useField` method to achieve reactivity is discouraged since it is designed to be used thoughtfully within the `form.Field` component. You might want to use `form.useStore` instead. ## Array Fields diff --git a/docs/framework/vue/guides/listeners.md b/docs/framework/vue/guides/listeners.md new file mode 100644 index 000000000..9c2d5abdf --- /dev/null +++ b/docs/framework/vue/guides/listeners.md @@ -0,0 +1,65 @@ +--- +id: listeners +title: Side effects for event triggers +--- + +For situations where you want to "affect" or "react" to triggers, there's the listener API. For example, if you, as the developer, want to reset a form field as a result of another field changing, you would use the listener API. + +Imagine the following user flow: + +- User selects a country from a drop-down. +- User then selects a province from another drop-down. +- User changes the selected country to a different one. + +In this example, when the user changes the country, the selected province needs to be reset as it's no longer valid. With the listener API, we can subscribe to the onChange event and dispatch a reset to the field "province" when the listener is fired. + +Events that can be "listened" to are: + +- onChange +- onBlur +- onMount +- onSubmit + +```vue + + + +``` diff --git a/docs/reference/classes/fieldapi.md b/docs/reference/classes/fieldapi.md index b462cda05..eb0c27709 100644 --- a/docs/reference/classes/fieldapi.md +++ b/docs/reference/classes/fieldapi.md @@ -45,7 +45,7 @@ Initializes a new `FieldApi` instance. #### Defined in -[packages/form-core/src/FieldApi.ts:440](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L440) +[packages/form-core/src/FieldApi.ts:509](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L509) ## Properties @@ -59,7 +59,7 @@ A reference to the form API instance. #### Defined in -[packages/form-core/src/FieldApi.ts:402](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L402) +[packages/form-core/src/FieldApi.ts:471](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L471) *** @@ -73,7 +73,7 @@ The field name. #### Defined in -[packages/form-core/src/FieldApi.ts:412](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L412) +[packages/form-core/src/FieldApi.ts:481](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L481) *** @@ -87,7 +87,7 @@ The field options. #### Defined in -[packages/form-core/src/FieldApi.ts:416](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L416) +[packages/form-core/src/FieldApi.ts:485](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L485) *** @@ -101,7 +101,7 @@ The current field state. #### Defined in -[packages/form-core/src/FieldApi.ts:430](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L430) +[packages/form-core/src/FieldApi.ts:499](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L499) *** @@ -115,7 +115,7 @@ The field state store. #### Defined in -[packages/form-core/src/FieldApi.ts:426](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L426) +[packages/form-core/src/FieldApi.ts:495](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L495) *** @@ -127,7 +127,7 @@ timeoutIds: Record; #### Defined in -[packages/form-core/src/FieldApi.ts:435](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L435) +[packages/form-core/src/FieldApi.ts:504](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L504) ## Methods @@ -145,7 +145,7 @@ Gets the field information object. #### Defined in -[packages/form-core/src/FieldApi.ts:658](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L658) +[packages/form-core/src/FieldApi.ts:738](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L738) *** @@ -163,7 +163,7 @@ Gets the current field metadata. #### Defined in -[packages/form-core/src/FieldApi.ts:636](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L636) +[packages/form-core/src/FieldApi.ts:716](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L716) *** @@ -185,7 +185,7 @@ Use `field.state.value` instead. #### Defined in -[packages/form-core/src/FieldApi.ts:616](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L616) +[packages/form-core/src/FieldApi.ts:690](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L690) *** @@ -203,7 +203,7 @@ Handles the blur event. #### Defined in -[packages/form-core/src/FieldApi.ts:1010](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L1010) +[packages/form-core/src/FieldApi.ts:1090](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L1090) *** @@ -225,7 +225,7 @@ Handles the change event. #### Defined in -[packages/form-core/src/FieldApi.ts:1003](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L1003) +[packages/form-core/src/FieldApi.ts:1083](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L1083) *** @@ -254,7 +254,7 @@ Inserts a value at the specified index, shifting the subsequent values to the ri #### Defined in -[packages/form-core/src/FieldApi.ts:671](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L671) +[packages/form-core/src/FieldApi.ts:751](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L751) *** @@ -276,7 +276,7 @@ Mounts the field instance to the form. #### Defined in -[packages/form-core/src/FieldApi.ts:531](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L531) +[packages/form-core/src/FieldApi.ts:600](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L600) *** @@ -305,7 +305,7 @@ Moves the value at the first specified index to the second specified index. #### Defined in -[packages/form-core/src/FieldApi.ts:701](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L701) +[packages/form-core/src/FieldApi.ts:781](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L781) *** @@ -329,7 +329,7 @@ Pushes a new value to the field. #### Defined in -[packages/form-core/src/FieldApi.ts:663](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L663) +[packages/form-core/src/FieldApi.ts:743](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L743) *** @@ -353,7 +353,7 @@ Removes a value at the specified index. #### Defined in -[packages/form-core/src/FieldApi.ts:689](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L689) +[packages/form-core/src/FieldApi.ts:769](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L769) *** @@ -382,7 +382,7 @@ Replaces a value at the specified index. #### Defined in -[packages/form-core/src/FieldApi.ts:680](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L680) +[packages/form-core/src/FieldApi.ts:760](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L760) *** @@ -404,7 +404,7 @@ Updates the field's errorMap #### Defined in -[packages/form-core/src/FieldApi.ts:1025](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L1025) +[packages/form-core/src/FieldApi.ts:1110](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L1110) *** @@ -426,7 +426,7 @@ Sets the field metadata. #### Defined in -[packages/form-core/src/FieldApi.ts:652](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L652) +[packages/form-core/src/FieldApi.ts:732](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L732) *** @@ -450,7 +450,7 @@ Sets the field value and run the `change` validator. #### Defined in -[packages/form-core/src/FieldApi.ts:623](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L623) +[packages/form-core/src/FieldApi.ts:697](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L697) *** @@ -479,7 +479,7 @@ Swaps the values at the specified indices. #### Defined in -[packages/form-core/src/FieldApi.ts:695](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L695) +[packages/form-core/src/FieldApi.ts:775](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L775) *** @@ -501,7 +501,7 @@ Updates the field instance with new options. #### Defined in -[packages/form-core/src/FieldApi.ts:579](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L579) +[packages/form-core/src/FieldApi.ts:653](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L653) *** @@ -523,4 +523,4 @@ Validates the field value. #### Defined in -[packages/form-core/src/FieldApi.ts:975](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L975) +[packages/form-core/src/FieldApi.ts:1055](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L1055) diff --git a/docs/reference/classes/formapi.md b/docs/reference/classes/formapi.md index e188f6067..3a6739ce4 100644 --- a/docs/reference/classes/formapi.md +++ b/docs/reference/classes/formapi.md @@ -121,7 +121,7 @@ deleteField(field): void #### Defined in -[packages/form-core/src/FormApi.ts:1105](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1105) +[packages/form-core/src/FormApi.ts:1116](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1116) *** @@ -147,7 +147,7 @@ Gets the field info of the specified field. #### Defined in -[packages/form-core/src/FormApi.ts:1016](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1016) +[packages/form-core/src/FormApi.ts:1027](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1027) *** @@ -173,7 +173,7 @@ Gets the metadata of the specified field. #### Defined in -[packages/form-core/src/FormApi.ts:1007](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1007) +[packages/form-core/src/FormApi.ts:1018](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1018) *** @@ -199,7 +199,7 @@ Gets the value of the specified field. #### Defined in -[packages/form-core/src/FormApi.ts:1000](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1000) +[packages/form-core/src/FormApi.ts:1011](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1011) *** @@ -253,7 +253,7 @@ Inserts a value into an array field at the specified index, shifting the subsequ #### Defined in -[packages/form-core/src/FormApi.ts:1137](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1137) +[packages/form-core/src/FormApi.ts:1148](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1148) *** @@ -305,7 +305,7 @@ Moves the value at the first specified index to the second specified index withi #### Defined in -[packages/form-core/src/FormApi.ts:1255](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1255) +[packages/form-core/src/FormApi.ts:1266](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1266) *** @@ -338,7 +338,7 @@ Pushes a value into an array field. #### Defined in -[packages/form-core/src/FormApi.ts:1119](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1119) +[packages/form-core/src/FormApi.ts:1130](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1130) *** @@ -371,7 +371,7 @@ Removes a value from an array field at the specified index. #### Defined in -[packages/form-core/src/FormApi.ts:1190](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1190) +[packages/form-core/src/FormApi.ts:1201](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1201) *** @@ -407,7 +407,7 @@ Replaces a value into an array field at the specified index. #### Defined in -[packages/form-core/src/FormApi.ts:1164](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1164) +[packages/form-core/src/FormApi.ts:1175](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1175) *** @@ -462,7 +462,7 @@ resetFieldMeta(fieldMeta): Record #### Defined in -[packages/form-core/src/FormApi.ts:1050](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1050) +[packages/form-core/src/FormApi.ts:1061](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1061) *** @@ -484,7 +484,7 @@ Updates the form's errorMap #### Defined in -[packages/form-core/src/FormApi.ts:1279](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1279) +[packages/form-core/src/FormApi.ts:1290](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1290) *** @@ -512,7 +512,7 @@ Updates the metadata of the specified field. #### Defined in -[packages/form-core/src/FormApi.ts:1035](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1035) +[packages/form-core/src/FormApi.ts:1046](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1046) *** @@ -545,7 +545,7 @@ Sets the value of the specified field and optionally updates the touched state. #### Defined in -[packages/form-core/src/FormApi.ts:1074](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1074) +[packages/form-core/src/FormApi.ts:1085](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1085) *** @@ -581,7 +581,7 @@ Swaps the values at the specified indices within an array field. #### Defined in -[packages/form-core/src/FormApi.ts:1229](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1229) +[packages/form-core/src/FormApi.ts:1240](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1240) *** diff --git a/docs/reference/index.md b/docs/reference/index.md index 1ff82aa4a..48e927f20 100644 --- a/docs/reference/index.md +++ b/docs/reference/index.md @@ -13,6 +13,7 @@ title: "@tanstack/form-core" ## Interfaces - [FieldApiOptions](interfaces/fieldapioptions.md) +- [FieldListeners](interfaces/fieldlisteners.md) - [FieldOptions](interfaces/fieldoptions.md) - [FieldValidators](interfaces/fieldvalidators.md) - [FormOptions](interfaces/formoptions.md) diff --git a/docs/reference/interfaces/fieldapioptions.md b/docs/reference/interfaces/fieldapioptions.md index 8f583b4e0..32032c9e7 100644 --- a/docs/reference/interfaces/fieldapioptions.md +++ b/docs/reference/interfaces/fieldapioptions.md @@ -39,7 +39,7 @@ If `true`, always run async validation, even if there are errors emitted during #### Defined in -[packages/form-core/src/FieldApi.ts:287](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L287) +[packages/form-core/src/FieldApi.ts:346](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L346) *** @@ -57,7 +57,7 @@ The default time to debounce async validation if there is not a more specific de #### Defined in -[packages/form-core/src/FieldApi.ts:283](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L283) +[packages/form-core/src/FieldApi.ts:342](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L342) *** @@ -75,7 +75,7 @@ An optional object with default metadata for the field. #### Defined in -[packages/form-core/src/FieldApi.ts:305](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L305) +[packages/form-core/src/FieldApi.ts:364](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L364) *** @@ -93,7 +93,7 @@ An optional default value for the field. #### Defined in -[packages/form-core/src/FieldApi.ts:279](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L279) +[packages/form-core/src/FieldApi.ts:338](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L338) *** @@ -105,7 +105,25 @@ form: FormApi; #### Defined in -[packages/form-core/src/FieldApi.ts:328](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L328) +[packages/form-core/src/FieldApi.ts:397](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L397) + +*** + +### listeners? + +```ts +optional listeners: FieldListeners; +``` + +A list of listeners which attach to the corresponding events + +#### Inherited from + +[`FieldOptions`](fieldoptions.md).[`listeners`](FieldOptions.md#listeners) + +#### Defined in + +[packages/form-core/src/FieldApi.ts:368](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L368) *** @@ -123,7 +141,7 @@ The field name. The type will be `DeepKeys` to ensure your name is #### Defined in -[packages/form-core/src/FieldApi.ts:275](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L275) +[packages/form-core/src/FieldApi.ts:334](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L334) *** @@ -141,7 +159,7 @@ A validator provided by an extension, like `yupValidator` from `@tanstack/yup-fo #### Defined in -[packages/form-core/src/FieldApi.ts:291](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L291) +[packages/form-core/src/FieldApi.ts:350](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L350) *** @@ -159,4 +177,4 @@ A list of validators to pass to the field #### Defined in -[packages/form-core/src/FieldApi.ts:295](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L295) +[packages/form-core/src/FieldApi.ts:354](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L354) diff --git a/docs/reference/interfaces/fieldlisteners.md b/docs/reference/interfaces/fieldlisteners.md new file mode 100644 index 000000000..859cabd59 --- /dev/null +++ b/docs/reference/interfaces/fieldlisteners.md @@ -0,0 +1,66 @@ +--- +id: FieldListeners +title: FieldListeners +--- + +# Interface: FieldListeners\ + +## Type Parameters + +• **TParentData** + +• **TName** *extends* [`DeepKeys`](../type-aliases/deepkeys.md)\<`TParentData`\> + +• **TFieldValidator** *extends* `Validator`\<[`DeepValue`](../type-aliases/deepvalue.md)\<`TParentData`, `TName`\>, `unknown`\> \| `undefined` = `undefined` + +• **TFormValidator** *extends* `Validator`\<`TParentData`, `unknown`\> \| `undefined` = `undefined` + +• **TData** *extends* [`DeepValue`](../type-aliases/deepvalue.md)\<`TParentData`, `TName`\> = [`DeepValue`](../type-aliases/deepvalue.md)\<`TParentData`, `TName`\> + +## Properties + +### onBlur? + +```ts +optional onBlur: FieldListenerFn; +``` + +#### Defined in + +[packages/form-core/src/FieldApi.ts:294](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L294) + +*** + +### onChange? + +```ts +optional onChange: FieldListenerFn; +``` + +#### Defined in + +[packages/form-core/src/FieldApi.ts:287](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L287) + +*** + +### onMount? + +```ts +optional onMount: FieldListenerFn; +``` + +#### Defined in + +[packages/form-core/src/FieldApi.ts:301](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L301) + +*** + +### onSubmit? + +```ts +optional onSubmit: FieldListenerFn; +``` + +#### Defined in + +[packages/form-core/src/FieldApi.ts:308](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L308) diff --git a/docs/reference/interfaces/fieldoptions.md b/docs/reference/interfaces/fieldoptions.md index a4103fe25..dffe07204 100644 --- a/docs/reference/interfaces/fieldoptions.md +++ b/docs/reference/interfaces/fieldoptions.md @@ -35,7 +35,7 @@ If `true`, always run async validation, even if there are errors emitted during #### Defined in -[packages/form-core/src/FieldApi.ts:287](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L287) +[packages/form-core/src/FieldApi.ts:346](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L346) *** @@ -49,7 +49,7 @@ The default time to debounce async validation if there is not a more specific de #### Defined in -[packages/form-core/src/FieldApi.ts:283](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L283) +[packages/form-core/src/FieldApi.ts:342](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L342) *** @@ -63,7 +63,7 @@ An optional object with default metadata for the field. #### Defined in -[packages/form-core/src/FieldApi.ts:305](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L305) +[packages/form-core/src/FieldApi.ts:364](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L364) *** @@ -77,7 +77,21 @@ An optional default value for the field. #### Defined in -[packages/form-core/src/FieldApi.ts:279](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L279) +[packages/form-core/src/FieldApi.ts:338](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L338) + +*** + +### listeners? + +```ts +optional listeners: FieldListeners; +``` + +A list of listeners which attach to the corresponding events + +#### Defined in + +[packages/form-core/src/FieldApi.ts:368](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L368) *** @@ -91,7 +105,7 @@ The field name. The type will be `DeepKeys` to ensure your name is #### Defined in -[packages/form-core/src/FieldApi.ts:275](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L275) +[packages/form-core/src/FieldApi.ts:334](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L334) *** @@ -105,7 +119,7 @@ A validator provided by an extension, like `yupValidator` from `@tanstack/yup-fo #### Defined in -[packages/form-core/src/FieldApi.ts:291](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L291) +[packages/form-core/src/FieldApi.ts:350](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L350) *** @@ -119,4 +133,4 @@ A list of validators to pass to the field #### Defined in -[packages/form-core/src/FieldApi.ts:295](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L295) +[packages/form-core/src/FieldApi.ts:354](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L354) diff --git a/docs/reference/interfaces/fieldvalidators.md b/docs/reference/interfaces/fieldvalidators.md index 57f9f54c2..5b1d8ff3f 100644 --- a/docs/reference/interfaces/fieldvalidators.md +++ b/docs/reference/interfaces/fieldvalidators.md @@ -36,7 +36,7 @@ z.string().min(1) // if `zodAdapter` is passed #### Defined in -[packages/form-core/src/FieldApi.ts:199](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L199) +[packages/form-core/src/FieldApi.ts:217](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L217) *** @@ -57,7 +57,7 @@ z.string().refine(async (val) => val.length > 3, { message: 'Testing 123' }) // #### Defined in -[packages/form-core/src/FieldApi.ts:212](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L212) +[packages/form-core/src/FieldApi.ts:230](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L230) *** @@ -73,7 +73,7 @@ If set to a number larger than 0, will debounce the async validation event by th #### Defined in -[packages/form-core/src/FieldApi.ts:225](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L225) +[packages/form-core/src/FieldApi.ts:243](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L243) *** @@ -87,7 +87,7 @@ An optional list of field names that should trigger this field's `onBlur` and `o #### Defined in -[packages/form-core/src/FieldApi.ts:229](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L229) +[packages/form-core/src/FieldApi.ts:247](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L247) *** @@ -108,7 +108,7 @@ z.string().min(1) // if `zodAdapter` is passed #### Defined in -[packages/form-core/src/FieldApi.ts:163](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L163) +[packages/form-core/src/FieldApi.ts:181](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L181) *** @@ -129,7 +129,7 @@ z.string().refine(async (val) => val.length > 3, { message: 'Testing 123' }) // #### Defined in -[packages/form-core/src/FieldApi.ts:176](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L176) +[packages/form-core/src/FieldApi.ts:194](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L194) *** @@ -145,7 +145,7 @@ If set to a number larger than 0, will debounce the async validation event by th #### Defined in -[packages/form-core/src/FieldApi.ts:188](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L188) +[packages/form-core/src/FieldApi.ts:206](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L206) *** @@ -159,7 +159,7 @@ An optional list of field names that should trigger this field's `onChange` and #### Defined in -[packages/form-core/src/FieldApi.ts:192](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L192) +[packages/form-core/src/FieldApi.ts:210](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L210) *** @@ -173,7 +173,7 @@ An optional function that takes a param of `formApi` which is a generic type of #### Defined in -[packages/form-core/src/FieldApi.ts:150](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L150) +[packages/form-core/src/FieldApi.ts:168](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L168) *** @@ -194,7 +194,7 @@ z.string().min(1) // if `zodAdapter` is passed #### Defined in -[packages/form-core/src/FieldApi.ts:236](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L236) +[packages/form-core/src/FieldApi.ts:254](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L254) *** @@ -215,4 +215,4 @@ z.string().refine(async (val) => val.length > 3, { message: 'Testing 123' }) // #### Defined in -[packages/form-core/src/FieldApi.ts:249](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L249) +[packages/form-core/src/FieldApi.ts:267](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L267) diff --git a/docs/reference/type-aliases/fieldmeta.md b/docs/reference/type-aliases/fieldmeta.md index 82277a280..8d1879752 100644 --- a/docs/reference/type-aliases/fieldmeta.md +++ b/docs/reference/type-aliases/fieldmeta.md @@ -71,4 +71,4 @@ A flag indicating whether the field is currently being validated. ## Defined in -[packages/form-core/src/FieldApi.ts:334](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L334) +[packages/form-core/src/FieldApi.ts:403](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L403) diff --git a/docs/reference/type-aliases/fieldstate.md b/docs/reference/type-aliases/fieldstate.md index c54a8fb32..eb141b621 100644 --- a/docs/reference/type-aliases/fieldstate.md +++ b/docs/reference/type-aliases/fieldstate.md @@ -35,4 +35,4 @@ The current value of the field. ## Defined in -[packages/form-core/src/FieldApi.ts:368](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L368) +[packages/form-core/src/FieldApi.ts:437](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L437) diff --git a/packages/angular-form/src/tanstack-field.directive.ts b/packages/angular-form/src/tanstack-field.directive.ts index 871649766..c23fa9189 100644 --- a/packages/angular-form/src/tanstack-field.directive.ts +++ b/packages/angular-form/src/tanstack-field.directive.ts @@ -9,6 +9,7 @@ import type { OnChanges, OnDestroy, OnInit } from '@angular/core' import type { DeepKeys, DeepValue, + FieldListeners, FieldMeta, FieldOptions, FieldValidators, @@ -53,6 +54,9 @@ export class TanStackField< @Input() validators?: NoInfer< FieldValidators > + @Input() listeners?: NoInfer< + FieldListeners + > @Input() defaultMeta?: Partial api!: FieldApi @@ -64,6 +68,7 @@ export class TanStackField< asyncAlways: this.asyncAlways, validatorAdapter: this.validatorAdapter, validators: this.validators, + listeners: this.listeners, defaultMeta: this.defaultMeta, name: this.name, form: this.tanstackField, diff --git a/packages/form-core/src/FieldApi.ts b/packages/form-core/src/FieldApi.ts index 6ca7a4b65..97b0ffc45 100644 --- a/packages/form-core/src/FieldApi.ts +++ b/packages/form-core/src/FieldApi.ts @@ -133,6 +133,24 @@ export type FieldAsyncValidateOrFn< TData > +/** + * @private + */ +export type FieldListenerFn< + TParentData, + TName extends DeepKeys, + TFieldValidator extends + | Validator, unknown> + | undefined = undefined, + TFormValidator extends + | Validator + | undefined = undefined, + TData extends DeepValue = DeepValue, +> = (props: { + value: TData + fieldApi: FieldApi +}) => void + export interface FieldValidators< TParentData, TName extends DeepKeys, @@ -255,6 +273,47 @@ export interface FieldValidators< > } +export interface FieldListeners< + TParentData, + TName extends DeepKeys, + TFieldValidator extends + | Validator, unknown> + | undefined = undefined, + TFormValidator extends + | Validator + | undefined = undefined, + TData extends DeepValue = DeepValue, +> { + onChange?: FieldListenerFn< + TParentData, + TName, + TFieldValidator, + TFormValidator, + TData + > + onBlur?: FieldListenerFn< + TParentData, + TName, + TFieldValidator, + TFormValidator, + TData + > + onMount?: FieldListenerFn< + TParentData, + TName, + TFieldValidator, + TFormValidator, + TData + > + onSubmit?: FieldListenerFn< + TParentData, + TName, + TFieldValidator, + TFormValidator, + TData + > +} + /** * An object type representing the options for a field in a form. */ @@ -303,6 +362,16 @@ export interface FieldOptions< * An optional object with default metadata for the field. */ defaultMeta?: Partial + /** + * A list of listeners which attach to the corresponding events + */ + listeners?: FieldListeners< + TParentData, + TName, + TFieldValidator, + TFormValidator, + TData + > } /** @@ -568,6 +637,11 @@ export class FieldApi< } } + this.options.listeners?.onMount?.({ + value: this.state.value, + fieldApi: this, + }) + return () => { unsubscribe() } @@ -622,6 +696,12 @@ export class FieldApi< */ setValue = (updater: Updater, options?: UpdateMetaOptions) => { this.form.setFieldValue(this.name, updater as never, options) + + this.options.listeners?.onChange?.({ + value: this.state.value, + fieldApi: this, + }) + this.validate('change') } @@ -1017,6 +1097,11 @@ export class FieldApi< this.setMeta((prev) => ({ ...prev, isBlurred: true })) } this.validate('blur') + + this.options.listeners?.onBlur?.({ + value: this.state.value, + fieldApi: this, + }) } /** diff --git a/packages/form-core/src/FormApi.ts b/packages/form-core/src/FormApi.ts index 353139d9f..5acac6e5f 100644 --- a/packages/form-core/src/FormApi.ts +++ b/packages/form-core/src/FormApi.ts @@ -980,6 +980,17 @@ export class FormApi< return } + this.store.batch(() => { + void ( + Object.values(this.fieldInfo) as FieldInfo[] + ).forEach((field) => { + field.instance?.options.listeners?.onSubmit?.({ + value: field.instance.state.value, + fieldApi: field.instance, + }) + }) + }) + try { // Run the submit code await this.options.onSubmit?.({ value: this.state.values, formApi: this }) diff --git a/packages/form-core/tests/FieldApi.spec.ts b/packages/form-core/tests/FieldApi.spec.ts index 590724c83..50756687b 100644 --- a/packages/form-core/tests/FieldApi.spec.ts +++ b/packages/form-core/tests/FieldApi.spec.ts @@ -932,6 +932,153 @@ describe('field api', () => { }) }) + it('should run listener onChange', () => { + const form = new FormApi({ + defaultValues: { + name: 'test', + }, + }) + + let triggered!: string + const field = new FieldApi({ + form, + name: 'name', + listeners: { + onChange: ({ value }) => { + triggered = value + }, + }, + }) + + field.mount() + + field.setValue('other') + expect(triggered).toStrictEqual('other') + }) + + it('should not run the listener onChange on mount', () => { + const form = new FormApi({ + defaultValues: { + name: 'test', + }, + }) + + let triggered!: string + const field = new FieldApi({ + form, + name: 'name', + listeners: { + onChange: ({ value }) => { + triggered = value + }, + }, + }) + + field.mount() + + expect(triggered).toStrictEqual(undefined) + }) + + it('should change the form state when running listener onChange', () => { + const form = new FormApi({ + defaultValues: { + name: 'foo', + greet: 'bar', + }, + }) + + const field = new FieldApi({ + form, + name: 'name', + listeners: { + onChange: ({ value }) => { + form.setFieldValue('greet', `hello ${value}`) + }, + }, + }) + + field.mount() + + field.setValue('baz') + expect(form.getFieldValue('name')).toStrictEqual('baz') + expect(form.getFieldValue('greet')).toStrictEqual('hello baz') + }) + + it('should reset the form on a listener', () => { + const form = new FormApi({ + defaultValues: { + name: 'foo', + greet: 'bar', + }, + }) + + const field = new FieldApi({ + form, + name: 'name', + listeners: { + onChange: () => { + form.reset({ + ...form.state.values, + greet: '', + }) + }, + }, + }) + + field.mount() + + field.setValue('other') + expect(form.getFieldValue('name')).toStrictEqual('other') + expect(form.getFieldValue('greet')).toStrictEqual('') + }) + + it('should run listener onBlur', () => { + const form = new FormApi({ + defaultValues: { + name: 'test', + }, + }) + + let triggered!: string + const field = new FieldApi({ + form, + name: 'name', + listeners: { + onBlur: ({ value }) => { + triggered = value + }, + }, + }) + + field.mount() + + field.handleBlur() + expect(triggered).toStrictEqual('test') + }) + + it('should run listener onMount', () => { + const form = new FormApi({ + defaultValues: { + name: 'test', + }, + }) + + let triggered!: string + const field = new FieldApi({ + form, + name: 'name', + listeners: { + onMount: ({ value }) => { + triggered = value + }, + }, + }) + + field.mount() + + expect(triggered).toStrictEqual('test') + }) + it('should contain multiple errors when running validation onBlur and onChange', () => { const form = new FormApi({ defaultValues: { diff --git a/packages/form-core/tests/FormApi.spec.ts b/packages/form-core/tests/FormApi.spec.ts index 65c0ae338..ee2b4b21d 100644 --- a/packages/form-core/tests/FormApi.spec.ts +++ b/packages/form-core/tests/FormApi.spec.ts @@ -1704,6 +1704,30 @@ describe('form api', () => { expect(form.state.errors).toStrictEqual(['first name is required']) }) + it('should run listener onSubmit', async () => { + const form = new FormApi({ + defaultValues: { + name: 'test', + }, + }) + + let triggered!: string + const field = new FieldApi({ + form, + name: 'name', + listeners: { + onSubmit: ({ value }) => { + triggered = value + }, + }, + }) + + field.mount() + await form.handleSubmit() + + expect(triggered).toStrictEqual('test') + }) + it('should update a nullable object', async () => { const form = new FormApi({ defaultValues: {