Skip to content
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

docs(solid-form): onChange listener -> onInput #1257

Merged
merged 3 commits into from
Mar 14, 2025
Merged
Show file tree
Hide file tree
Changes from 2 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
4 changes: 2 additions & 2 deletions docs/framework/solid/guides/basic-concepts.md
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ Example:
name={field().name}
value={field().state.value}
onBlur={field().handleBlur}
onChange={(e) => field().handleChange(e.target.value)}
onInput={(e) => field().handleChange(e.target.value)}
/>
<button
type="button"
Expand All @@ -261,7 +261,7 @@ Example:
name={field().name}
value={field().state.value}
onBlur={field().handleBlur}
onChange={(e) => field().handleChange(e.target.value)}
onInput={(e) => field().handleChange(e.target.value)}
/>
</div>
);
Expand Down
14 changes: 7 additions & 7 deletions docs/framework/solid/guides/validation.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ Here is an example:
name={field().name}
value={field().state.value}
type="number"
onChange={(e) => field().handleChange(e.target.valueAsNumber)}
onInput={(e) => field().handleChange(e.target.valueAsNumber)}
/>
{field().state.meta.errors ? (
<em role="alert">{field().state.meta.errors.join(', ')}</em>
Expand Down Expand Up @@ -61,8 +61,8 @@ In the example above, the validation is done at each keystroke (`onChange`). If,
type="number"
// Listen to the onBlur event on the field
onBlur={field().handleBlur}
// We always need to implement onChange, so that TanStack Form receives the changes
onChange={(e) => field().handleChange(e.target.valueAsNumber)}
// We always need to implement onInput, so that TanStack Form receives the changes
onInput={(e) => field().handleChange(e.target.valueAsNumber)}
/>
{field().state.meta.errors ? (
<em role="alert">{field().state.meta.errors.join(', ')}</em>
Expand Down Expand Up @@ -93,8 +93,8 @@ So you can control when the validation is done by implementing the desired callb
type="number"
// Listen to the onBlur event on the field
onBlur={field().handleBlur}
// We always need to implement onChange, so that TanStack Form receives the changes
onChange={(e) => field().handleChange(e.target.valueAsNumber)}
// We always need to implement onInput, so that TanStack Form receives the changes
onInput={(e) => field().handleChange(e.target.valueAsNumber)}
/>
{field().state.meta.errors ? (
<em role="alert">{field().state.meta.errors.join(', ')}</em>
Expand Down Expand Up @@ -246,7 +246,7 @@ To do this, we have dedicated `onChangeAsync`, `onBlurAsync`, and other methods
name={field().name}
value={field().state.value}
type="number"
onChange={(e) => field().handleChange(e.target.valueAsNumber)}
onInput={(e) => field().handleChange(e.target.valueAsNumber)}
/>
{field().state.meta.errors ? (
<em role="alert">{field().state.meta.errors.join(', ')}</em>
Expand Down Expand Up @@ -278,7 +278,7 @@ Synchronous and Asynchronous validations can coexist. For example, it is possibl
value={field().state.value}
type="number"
onBlur={field().handleBlur}
onChange={(e) => field().handleChange(e.target.valueAsNumber)}
onInput={(e) => field().handleChange(e.target.valueAsNumber)}
/>
{field().state.meta.errors ? (
<em role="alert">{field().state.meta.errors.join(', ')}</em>
Expand Down
36 changes: 31 additions & 5 deletions examples/react/query-integration/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,20 +20,40 @@ function FieldInfo({ field }: { field: AnyFieldApi }) {
)
}

class DB {
private data: { firstName: string; lastName: string }

constructor() {
this.data = { firstName: 'FirstName', lastName: 'LastName' }
}

getData(): { firstName: string; lastName: string } {
return { ...this.data }
}

async saveUser(value: { firstName: string; lastName: string }) {
this.data = value
return value
}
}

// Dummy Database to emulate server-side actions
// This will show you the robustness of react-query integration
const db = new DB()

export default function App() {
const { data, isLoading } = useQuery({
const { data, isLoading, refetch } = useQuery({
queryKey: ['data'],
queryFn: async () => {
await new Promise((resolve) => setTimeout(resolve, 1000))
return { firstName: 'FirstName', lastName: 'LastName' }
return db.getData()
},
})

const saveUserMutation = useMutation({
mutationFn: async (value: { firstName: string; lastName: string }) => {
await new Promise((resolve) => setTimeout(resolve, 1000))
console.log(value)
return value
db.saveUser(value)
},
})

Expand All @@ -42,9 +62,15 @@ export default function App() {
firstName: data?.firstName ?? '',
lastName: data?.lastName ?? '',
},
onSubmit: async ({ value }) => {
onSubmit: async ({ formApi, value }) => {
// Do something with form data
await saveUserMutation.mutateAsync(value)

// Invalidating query to recheck fresh data
await refetch()

// Reset the form to start-over with a clean state
formApi.reset()
},
})

Expand Down