-
-
Notifications
You must be signed in to change notification settings - Fork 607
fix(listeners): rename onFieldUnmount to match that of the other listeners #2103
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| --- | ||
| '@tanstack/form-core': minor | ||
| --- | ||
|
|
||
| Rename `onFieldUnmount` listener to `onUnmount` to match the naming convention of other form listeners. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -11,7 +11,7 @@ Imagine the following user flow: | |
| - 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. | ||
| 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 "province" field when the listener is fired. | ||
|
|
||
| Events that can be "listened" to are: | ||
|
|
||
|
|
@@ -60,3 +60,79 @@ export class AppComponent { | |
| } | ||
| } | ||
| ``` | ||
|
|
||
| ## Built-in Debouncing | ||
|
|
||
| If you are making an API request inside a listener, you may want to debounce the calls as it can lead to performance issues. | ||
| We enable an easy method for debouncing your listeners by adding a `onChangeDebounceMs` or `onBlurDebounceMs`. | ||
|
|
||
| ```angular-ts | ||
| @Component({ | ||
| selector: 'app-root', | ||
| standalone: true, | ||
| imports: [TanStackField], | ||
| template: ` | ||
| <ng-container | ||
| [tanstackField]="form" | ||
| name="country" | ||
| [listeners]="{ | ||
| onChangeDebounceMs: 500, | ||
| onChange: onCountryChange | ||
| }" | ||
| #country="field" | ||
| ></ng-container> | ||
| `, | ||
| }) | ||
| export class AppComponent { | ||
| form = injectForm({ | ||
| defaultValues: { | ||
| country: '', | ||
| province: '', | ||
| }, | ||
| }) | ||
|
|
||
| onCountryChange: FieldListenerFn<any, any, any, any, string> = ({ | ||
| value, | ||
| }) => { | ||
| console.log(`Country changed to: ${value} without a change within 500ms, resetting province`) | ||
| this.form.setFieldValue('province', '') | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| ## Form listeners | ||
|
|
||
| At a higher level, listeners are also available at the form level, allowing you access to the `onMount` and `onSubmit` events, and having `onChange`, `onBlur`, and `onUnmount` propagated to all the form's children. Form-level listeners can also be debounced in the same way as previously discussed. | ||
|
|
||
| `onMount` and `onSubmit` listeners have the following parameters: | ||
|
|
||
| - `formApi` | ||
|
|
||
|
Comment on lines
+107
to
+110
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
This section says 🤖 Prompt for AI Agents |
||
| `onChange`, `onBlur`, and `onUnmount` listeners have access to: | ||
|
|
||
| - `fieldApi` | ||
| - `formApi` | ||
|
|
||
| ```angular-ts | ||
| export class AppComponent { | ||
| form = injectForm({ | ||
| listeners: { | ||
| onMount: ({ formApi }) => { | ||
| // custom logging service | ||
| loggingService('mount', formApi.state.values) | ||
| }, | ||
|
|
||
| onChange: ({ formApi, fieldApi }) => { | ||
| // autosave logic | ||
| if (formApi.state.isValid) { | ||
| formApi.handleSubmit() | ||
| } | ||
|
|
||
| // fieldApi represents the field that triggered the event. | ||
| console.log(fieldApi.name, fieldApi.state.value) | ||
| }, | ||
| onChangeDebounceMs: 500, | ||
| }, | ||
| }) | ||
| } | ||
| ``` | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,126 @@ | ||
| --- | ||
| 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 "province" field when the listener is fired. | ||
|
|
||
| Events that can be "listened" to are: | ||
|
|
||
| - `onChange` | ||
| - `onBlur` | ||
| - `onMount` | ||
| - `onSubmit` | ||
| - `onUnmount` | ||
|
|
||
| ```ts | ||
| ${this.#form.field( | ||
| { | ||
| name: 'country', | ||
| listeners: { | ||
| onChange: ({ value }) => { | ||
| console.log(`Country changed to: ${value}, resetting province`) | ||
| this.#form.api.setFieldValue('province', '') | ||
| }, | ||
| }, | ||
| }, | ||
| (field) => { | ||
| return html` | ||
| <label> | ||
| <div>Country</div> | ||
| <input | ||
| .value="${field.state.value}" | ||
| @input="${(e: Event) => { | ||
| const target = e.target as HTMLInputElement | ||
| field.handleChange(target.value) | ||
| }}" | ||
| /> | ||
| </label> | ||
| ` | ||
| }, | ||
| )} | ||
|
|
||
| ${this.#form.field( | ||
| { name: 'province' }, | ||
| (field) => { | ||
| return html` | ||
| <label> | ||
| <div>Province</div> | ||
| <input | ||
| .value="${field.state.value}" | ||
| @input="${(e: Event) => { | ||
| const target = e.target as HTMLInputElement | ||
| field.handleChange(target.value) | ||
| }}" | ||
| /> | ||
| </label> | ||
| ` | ||
| }, | ||
| )} | ||
| ``` | ||
|
|
||
| ## Built-in Debouncing | ||
|
|
||
| If you are making an API request inside a listener, you may want to debounce the calls as it can lead to performance issues. | ||
| We enable an easy method for debouncing your listeners by adding a `onChangeDebounceMs` or `onBlurDebounceMs`. | ||
|
|
||
| ```ts | ||
| ${this.#form.field( | ||
| { | ||
| name: 'country', | ||
| listeners: { | ||
| onChangeDebounceMs: 500, // 500ms debounce | ||
| onChange: ({ value }) => { | ||
| console.log(`Country changed to: ${value} without a change within 500ms, resetting province`) | ||
| this.#form.api.setFieldValue('province', '') | ||
| }, | ||
| }, | ||
| }, | ||
| (field) => { | ||
| return html`<!-- ... -->` | ||
| }, | ||
| )} | ||
| ``` | ||
|
|
||
| ## Form listeners | ||
|
|
||
| At a higher level, listeners are also available at the form level, allowing you access to the `onMount` and `onSubmit` events, and having `onChange`, `onBlur`, and `onUnmount` propagated to all the form's children. Form-level listeners can also be debounced in the same way as previously discussed. | ||
|
|
||
| `onMount` and `onSubmit` listeners have the following parameters: | ||
|
|
||
| - `formApi` | ||
|
|
||
|
Comment on lines
+97
to
+100
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
🤖 Prompt for AI Agents |
||
| `onChange`, `onBlur`, and `onUnmount` listeners have access to: | ||
|
|
||
| - `fieldApi` | ||
| - `formApi` | ||
|
|
||
| ```ts | ||
| #form = new TanStackFormController(this, { | ||
| listeners: { | ||
| onMount: ({ formApi }) => { | ||
| // custom logging service | ||
| loggingService('mount', formApi.state.values) | ||
| }, | ||
|
|
||
| onChange: ({ formApi, fieldApi }) => { | ||
| // autosave logic | ||
| if (formApi.state.isValid) { | ||
| formApi.handleSubmit() | ||
| } | ||
|
|
||
| // fieldApi represents the field that triggered the event. | ||
| console.log(fieldApi.name, fieldApi.state.value) | ||
| }, | ||
| onChangeDebounceMs: 500, | ||
| }, | ||
| }) | ||
| ``` | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,127 @@ | ||
| --- | ||
| 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 "province" field when the listener is fired. | ||
|
|
||
| Events that can be "listened" to are: | ||
|
|
||
| - `onChange` | ||
| - `onBlur` | ||
| - `onMount` | ||
| - `onSubmit` | ||
| - `onUnmount` | ||
|
|
||
| ```tsx | ||
| export default function App() { | ||
| const form = createForm(() => ({ | ||
| defaultValues: { | ||
| country: '', | ||
| province: '', | ||
| }, | ||
| // ... | ||
| })) | ||
|
|
||
| return ( | ||
| <div> | ||
| <form.Field | ||
| name="country" | ||
| listeners={{ | ||
| onChange: ({ value }) => { | ||
| console.log(`Country changed to: ${value}, resetting province`) | ||
| form.setFieldValue('province', '') | ||
| }, | ||
| }} | ||
| > | ||
| {(field) => ( | ||
| <label> | ||
| <div>Country</div> | ||
| <input | ||
| value={field().state.value} | ||
| onChange={(e) => field().handleChange(e.target.value)} | ||
| /> | ||
| </label> | ||
| )} | ||
| </form.Field> | ||
|
|
||
| <form.Field name="province"> | ||
| {(field) => ( | ||
| <label> | ||
| <div>Province</div> | ||
| <input | ||
| value={field().state.value} | ||
| onChange={(e) => field().handleChange(e.target.value)} | ||
| /> | ||
| </label> | ||
| )} | ||
| </form.Field> | ||
| </div> | ||
| ) | ||
| } | ||
| ``` | ||
|
|
||
| ## Built-in Debouncing | ||
|
|
||
| If you are making an API request inside a listener, you may want to debounce the calls as it can lead to performance issues. | ||
| We enable an easy method for debouncing your listeners by adding a `onChangeDebounceMs` or `onBlurDebounceMs`. | ||
|
|
||
| ```tsx | ||
| <form.Field | ||
| name="country" | ||
| listeners={{ | ||
| onChangeDebounceMs: 500, // 500ms debounce | ||
| onChange: ({ value }) => { | ||
| console.log(`Country changed to: ${value} without a change within 500ms, resetting province`) | ||
| form.setFieldValue('province', '') | ||
| }, | ||
| }} | ||
| > | ||
| {(field) => ( | ||
| /* ... */ | ||
| )} | ||
| </form.Field> | ||
| ``` | ||
|
|
||
| ## Form listeners | ||
|
|
||
| At a higher level, listeners are also available at the form level, allowing you access to the `onMount` and `onSubmit` events, and having `onChange`, `onBlur`, and `onUnmount` propagated to all the form's children. Form-level listeners can also be debounced in the same way as previously discussed. | ||
|
|
||
| `onMount` and `onSubmit` listeners have the following parameters: | ||
|
|
||
| - `formApi` | ||
|
|
||
|
Comment on lines
+98
to
+101
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The docs currently imply 🤖 Prompt for AI Agents |
||
| `onChange`, `onBlur`, and `onUnmount` listeners have access to: | ||
|
|
||
| - `fieldApi` | ||
| - `formApi` | ||
|
|
||
| ```tsx | ||
| const form = createForm(() => ({ | ||
| listeners: { | ||
| onMount: ({ formApi }) => { | ||
| // custom logging service | ||
| loggingService('mount', formApi.state.values) | ||
| }, | ||
|
|
||
| onChange: ({ formApi, fieldApi }) => { | ||
| // autosave logic | ||
| if (formApi.state.isValid) { | ||
| formApi.handleSubmit() | ||
| } | ||
|
|
||
| // fieldApi represents the field that triggered the event. | ||
| console.log(fieldApi.name, fieldApi.state.value) | ||
| }, | ||
| onChangeDebounceMs: 500, | ||
| }, | ||
| })) | ||
| ``` | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This rename is breaking; the release type should be
major(or keep backward compatibility).Line 2 marks this as
minor, but removing/renaming a public listener key breaks existing consumers usingonFieldUnmount.Suggested changeset fix
📝 Committable suggestion
🤖 Prompt for AI Agents