Async validation
In this example, we add an async username avaliability check to our form. We also validate it on the server, of course ๐
import { InputError } from 'composable-functions'
const schema = z.object({
username: z.string().min(1),
password: z.string().min(1),
})
const takenUsernames = ['foo', 'bar']
export const loader = ({ request }: Route.LoaderArgs) => {
const url = new URL(request.url)
const username = url.searchParams.get('username')
if (username && takenUsernames.includes(username)) {
return { message: 'Already taken' }
}
return null
}
const mutation = applySchema(schema)(async (values) => {
if (takenUsernames.includes(values.username)) {
throw new InputError('Already taken', ['username'])
}
return values
})
export const action = async ({ request }: Route.ActionArgs) =>
formAction({ request, schema, mutation })
export default function Component() {
const fetcher = useFetcher<{ message: string }>()
const message = fetcher.data?.message
return (
<SchemaForm schema={schema}>
{({ Field, Errors, Button, clearErrors }) => (
<>
<Field name="username">
{({ Label, Input, Errors, Error }) => (
<>
<Label />
<Input
onChange={(event) => {
clearErrors('username')
fetcher.load(
`/examples/forms/async-validation?username=${event.target.value}`,
)
}}
/>
<Errors />
{message && <Error>{message}</Error>}
</>
)}
</Field>
<Field name="password" />
<Errors />
<Button disabled={Boolean(message)} />
</>
)}
</SchemaForm>
)
}