Skip to content
Open
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
5 changes: 5 additions & 0 deletions .changeset/rename-onFieldUnmount-to-onUnmount.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@tanstack/form-core': minor
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

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 using onFieldUnmount.

Suggested changeset fix
-'@tanstack/form-core': minor
+'@tanstack/form-core': major
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
'@tanstack/form-core': minor
'@tanstack/form-core': major
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.changeset/rename-onFieldUnmount-to-onUnmount.md at line 2, The changeset
incorrectly marks the rename of the public listener key onFieldUnmount to
onUnmount as a minor change; update the changeset in
.changeset/rename-onFieldUnmount-to-onUnmount.md to use a major release type (or
alternatively implement and document a backward-compatible alias that preserves
onFieldUnmount while introducing onUnmount) so existing consumers are not
broken—refer to the public listener key names onFieldUnmount and onUnmount and
ensure the changeset reflects the breaking change or that compatibility code is
added.

---

Rename `onFieldUnmount` listener to `onUnmount` to match the naming convention of other form listeners.
78 changes: 77 additions & 1 deletion docs/framework/angular/guides/listeners.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:

Expand Down Expand Up @@ -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
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

onSubmit callback params are documented incorrectly.

This section says onSubmit only receives formApi, but FormListeners.onSubmit in packages/form-core/src/FormApi.ts (Line 292-308) is typed as { formApi, meta }. Please update docs to list meta for onSubmit to avoid incorrect handler signatures.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/framework/angular/guides/listeners.md` around lines 107 - 110, The docs
incorrectly state that onSubmit only receives formApi; update the listeners
documentation so onSubmit lists both parameters (formApi and meta) to match the
FormListeners.onSubmit signature in FormApi.ts. Locate the onSubmit entry in the
listeners doc (near the onMount/onSubmit section) and add "meta" to the
parameter list and description so handler examples and types match the
FormListeners.onSubmit ({ formApi, meta }) usage.

`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,
},
})
}
```
126 changes: 126 additions & 0 deletions docs/framework/lit/guides/listeners.md
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
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

onSubmit listener signature is incomplete in this guide.

onSubmit is documented as formApi-only, but core API typing in packages/form-core/src/FormApi.ts includes meta ({ formApi, meta }). Please correct this section and the adjacent example wording.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/framework/lit/guides/listeners.md` around lines 97 - 100, The guide
incorrectly documents the onSubmit listener as taking only formApi; update the
signature and examples to include the second parameter meta (i.e.,
onSubmit(formApi, meta)) to match the core typing in FormApi (see
packages/form-core/src/FormApi.ts), and adjust adjacent example wording to
reference both formApi and meta where applicable.

`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,
},
})
```
4 changes: 2 additions & 2 deletions docs/framework/react/guides/listeners.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,13 +93,13 @@ We enable an easy method for debouncing your listeners by adding a `onChangeDebo

### 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` and `onBlur` propagated to all the form's children. Form-level listeners can also be debounced in the same way as previously discussed.
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`

`onChange` and `onBlur` listeners have access to:
`onChange`, `onBlur`, and `onUnmount` listeners have access to:

- `fieldApi`
- `formApi`
Expand Down
127 changes: 127 additions & 0 deletions docs/framework/solid/guides/listeners.md
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
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

onSubmit parameter docs are missing meta.

The docs currently imply onSubmit gets only formApi, but packages/form-core/src/FormApi.ts defines onSubmit props as { formApi, meta }. Please document meta explicitly for Solid as well.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/framework/solid/guides/listeners.md` around lines 98 - 101, The docs for
Solid's listeners incorrectly list only `formApi` for `onSubmit`; update the
listeners.md entry so `onSubmit` is documented as receiving `{ formApi, meta }`
(matching the definition in packages/form-core/src/FormApi.ts), describe `meta`
briefly (e.g., submission metadata such as submission count or validation
state), and ensure the `onMount` listing remains unchanged; locate the
`onSubmit` listener section in listeners.md and add `meta` to the parameter list
and its short description.

`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,
},
}))
```
Loading
Loading