Skip to content

Commit 0ba2718

Browse files
committed
fix(listeners): rename unmount to match that of the other listeners
1 parent 4e7c8a6 commit 0ba2718

11 files changed

Lines changed: 535 additions & 9 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@tanstack/form-core": minor
3+
---
4+
5+
Rename `onFieldUnmount` listener to `onUnmount` to match the naming convention of other form listeners.

docs/framework/angular/guides/listeners.md

Lines changed: 77 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ Imagine the following user flow:
1111
- User then selects a province from another drop-down.
1212
- User changes the selected country to a different one.
1313

14-
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.
14+
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.
1515

1616
Events that can be "listened" to are:
1717

@@ -60,3 +60,79 @@ export class AppComponent {
6060
}
6161
}
6262
```
63+
64+
## Built-in Debouncing
65+
66+
If you are making an API request inside a listener, you may want to debounce the calls as it can lead to performance issues.
67+
We enable an easy method for debouncing your listeners by adding a `onChangeDebounceMs` or `onBlurDebounceMs`.
68+
69+
```angular-ts
70+
@Component({
71+
selector: 'app-root',
72+
standalone: true,
73+
imports: [TanStackField],
74+
template: `
75+
<ng-container
76+
[tanstackField]="form"
77+
name="country"
78+
[listeners]="{
79+
onChangeDebounceMs: 500,
80+
onChange: onCountryChange
81+
}"
82+
#country="field"
83+
></ng-container>
84+
`,
85+
})
86+
export class AppComponent {
87+
form = injectForm({
88+
defaultValues: {
89+
country: '',
90+
province: '',
91+
},
92+
})
93+
94+
onCountryChange: FieldListenerFn<any, any, any, any, string> = ({
95+
value,
96+
}) => {
97+
console.log(`Country changed to: ${value} without a change within 500ms, resetting province`)
98+
this.form.setFieldValue('province', '')
99+
}
100+
}
101+
```
102+
103+
## Form listeners
104+
105+
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.
106+
107+
`onMount` and `onSubmit` listeners have the following parameters:
108+
109+
- `formApi`
110+
111+
`onChange`, `onBlur`, and `onUnmount` listeners have access to:
112+
113+
- `fieldApi`
114+
- `formApi`
115+
116+
```angular-ts
117+
export class AppComponent {
118+
form = injectForm({
119+
listeners: {
120+
onMount: ({ formApi }) => {
121+
// custom logging service
122+
loggingService('mount', formApi.state.values)
123+
},
124+
125+
onChange: ({ formApi, fieldApi }) => {
126+
// autosave logic
127+
if (formApi.state.isValid) {
128+
formApi.handleSubmit()
129+
}
130+
131+
// fieldApi represents the field that triggered the event.
132+
console.log(fieldApi.name, fieldApi.state.value)
133+
},
134+
onChangeDebounceMs: 500,
135+
},
136+
})
137+
}
138+
```
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
---
2+
id: listeners
3+
title: Side effects for event triggers
4+
---
5+
6+
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.
7+
8+
Imagine the following user flow:
9+
10+
- User selects a country from a drop-down.
11+
- User then selects a province from another drop-down.
12+
- User changes the selected country to a different one.
13+
14+
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.
15+
16+
Events that can be "listened" to are:
17+
18+
- `onChange`
19+
- `onBlur`
20+
- `onMount`
21+
- `onSubmit`
22+
- `onUnmount`
23+
24+
```ts
25+
${this.#form.field(
26+
{
27+
name: 'country',
28+
listeners: {
29+
onChange: ({ value }) => {
30+
console.log(`Country changed to: ${value}, resetting province`)
31+
this.#form.api.setFieldValue('province', '')
32+
},
33+
},
34+
},
35+
(field) => {
36+
return html`
37+
<label>
38+
<div>Country</div>
39+
<input
40+
.value="${field.state.value}"
41+
@input="${(e: Event) => {
42+
const target = e.target as HTMLInputElement
43+
field.handleChange(target.value)
44+
}}"
45+
/>
46+
</label>
47+
`
48+
},
49+
)}
50+
51+
${this.#form.field(
52+
{ name: 'province' },
53+
(field) => {
54+
return html`
55+
<label>
56+
<div>Province</div>
57+
<input
58+
.value="${field.state.value}"
59+
@input="${(e: Event) => {
60+
const target = e.target as HTMLInputElement
61+
field.handleChange(target.value)
62+
}}"
63+
/>
64+
</label>
65+
`
66+
},
67+
)}
68+
```
69+
70+
## Built-in Debouncing
71+
72+
If you are making an API request inside a listener, you may want to debounce the calls as it can lead to performance issues.
73+
We enable an easy method for debouncing your listeners by adding a `onChangeDebounceMs` or `onBlurDebounceMs`.
74+
75+
```ts
76+
${this.#form.field(
77+
{
78+
name: 'country',
79+
listeners: {
80+
onChangeDebounceMs: 500, // 500ms debounce
81+
onChange: ({ value }) => {
82+
console.log(`Country changed to: ${value} without a change within 500ms, resetting province`)
83+
this.#form.api.setFieldValue('province', '')
84+
},
85+
},
86+
},
87+
(field) => {
88+
return html`<!-- ... -->`
89+
},
90+
)}
91+
```
92+
93+
## Form listeners
94+
95+
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.
96+
97+
`onMount` and `onSubmit` listeners have the following parameters:
98+
99+
- `formApi`
100+
101+
`onChange`, `onBlur`, and `onUnmount` listeners have access to:
102+
103+
- `fieldApi`
104+
- `formApi`
105+
106+
```ts
107+
#form = new TanStackFormController(this, {
108+
listeners: {
109+
onMount: ({ formApi }) => {
110+
// custom logging service
111+
loggingService('mount', formApi.state.values)
112+
},
113+
114+
onChange: ({ formApi, fieldApi }) => {
115+
// autosave logic
116+
if (formApi.state.isValid) {
117+
formApi.handleSubmit()
118+
}
119+
120+
// fieldApi represents the field that triggered the event.
121+
console.log(fieldApi.name, fieldApi.state.value)
122+
},
123+
onChangeDebounceMs: 500,
124+
},
125+
})
126+
```

docs/framework/react/guides/listeners.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,13 +93,13 @@ We enable an easy method for debouncing your listeners by adding a `onChangeDebo
9393

9494
### Form listeners
9595

96-
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.
96+
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.
9797

9898
`onMount` and `onSubmit` listeners have the following parameters:
9999

100100
- `formApi`
101101

102-
`onChange` and `onBlur` listeners have access to:
102+
`onChange`, `onBlur`, and `onUnmount` listeners have access to:
103103

104104
- `fieldApi`
105105
- `formApi`
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
---
2+
id: listeners
3+
title: Side effects for event triggers
4+
---
5+
6+
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.
7+
8+
Imagine the following user flow:
9+
10+
- User selects a country from a drop-down.
11+
- User then selects a province from another drop-down.
12+
- User changes the selected country to a different one.
13+
14+
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.
15+
16+
Events that can be "listened" to are:
17+
18+
- `onChange`
19+
- `onBlur`
20+
- `onMount`
21+
- `onSubmit`
22+
- `onUnmount`
23+
24+
```tsx
25+
export default function App() {
26+
const form = createForm(() => ({
27+
defaultValues: {
28+
country: '',
29+
province: '',
30+
},
31+
// ...
32+
}))
33+
34+
return (
35+
<div>
36+
<form.Field
37+
name="country"
38+
listeners={{
39+
onChange: ({ value }) => {
40+
console.log(`Country changed to: ${value}, resetting province`)
41+
form.setFieldValue('province', '')
42+
},
43+
}}
44+
>
45+
{(field) => (
46+
<label>
47+
<div>Country</div>
48+
<input
49+
value={field().state.value}
50+
onChange={(e) => field().handleChange(e.target.value)}
51+
/>
52+
</label>
53+
)}
54+
</form.Field>
55+
56+
<form.Field name="province">
57+
{(field) => (
58+
<label>
59+
<div>Province</div>
60+
<input
61+
value={field().state.value}
62+
onChange={(e) => field().handleChange(e.target.value)}
63+
/>
64+
</label>
65+
)}
66+
</form.Field>
67+
</div>
68+
)
69+
}
70+
```
71+
72+
## Built-in Debouncing
73+
74+
If you are making an API request inside a listener, you may want to debounce the calls as it can lead to performance issues.
75+
We enable an easy method for debouncing your listeners by adding a `onChangeDebounceMs` or `onBlurDebounceMs`.
76+
77+
```tsx
78+
<form.Field
79+
name="country"
80+
listeners={{
81+
onChangeDebounceMs: 500, // 500ms debounce
82+
onChange: ({ value }) => {
83+
console.log(`Country changed to: ${value} without a change within 500ms, resetting province`)
84+
form.setFieldValue('province', '')
85+
},
86+
}}
87+
>
88+
{(field) => (
89+
/* ... */
90+
)}
91+
</form.Field>
92+
```
93+
94+
## Form listeners
95+
96+
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.
97+
98+
`onMount` and `onSubmit` listeners have the following parameters:
99+
100+
- `formApi`
101+
102+
`onChange`, `onBlur`, and `onUnmount` listeners have access to:
103+
104+
- `fieldApi`
105+
- `formApi`
106+
107+
```tsx
108+
const form = createForm(() => ({
109+
listeners: {
110+
onMount: ({ formApi }) => {
111+
// custom logging service
112+
loggingService('mount', formApi.state.values)
113+
},
114+
115+
onChange: ({ formApi, fieldApi }) => {
116+
// autosave logic
117+
if (formApi.state.isValid) {
118+
formApi.handleSubmit()
119+
}
120+
121+
// fieldApi represents the field that triggered the event.
122+
console.log(fieldApi.name, fieldApi.state.value)
123+
},
124+
onChangeDebounceMs: 500,
125+
},
126+
}))
127+
```

0 commit comments

Comments
 (0)