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

Qwik: Form not working when schema is declared inside component$ #167

Open
DevHusariaSolutions opened this issue Jan 2, 2024 · 9 comments
Assignees
Labels
question Further information is requested

Comments

@DevHusariaSolutions
Copy link

Example in docs is omitting important part of validation libraries - custom errors.
If we have multi-lang website content of such errors is derived by hook function which returns translated content, but hook needs to be used inside component, so schema also needs to be defined in component. When doing so I gets error

r: Qrl($) scope is not a function, but it's capturing local identifiers: formSchema

where formSchema is variable name of my validation schema.

Moving formSchema outside component works, but ofc I won't be able to define custom errors for it.

Please publish advanced example of Your solution.

@fabian-hiller
Copy link
Owner

Just wrap your schema with zodForm$ or valiForm$ and pass the returned value to .validate of useForm. Please share your code if you need more help. If you are using Valibot, we plan to improve i18n to allow you to define your translations and schemas globally.

export default component$(() => {
  const LoginSchema = valiForm$(
    v.object({
      email: v.string([
        v.minLength(1, 'Please enter your email.'),
        v.email('The email address is badly formatted.'),
      ]),
      password: v.string([
        v.minLength(1, 'Please enter your password.'),
        v.minLength(8, 'You password must have 8 characters or more.'),
      ]),
    })
  );

  // Use login form
  const [loginForm, { Form, Field }] = useForm<LoginForm>({
    loader: useFormLoader(),
    action: useFormAction(),
    validate: LoginSchema,
  });
  
 // More code here...

@fabian-hiller fabian-hiller self-assigned this Jan 3, 2024
@fabian-hiller fabian-hiller added the question Further information is requested label Jan 3, 2024
@DevHusariaSolutions
Copy link
Author

DevHusariaSolutions commented Jan 3, 2024

I've already tried this, no result of change. I don't use loader as function, I use plain object.

To test it You can use

import { $, component$, useStore, type QRL } from '@builder.io/qwik'
import type { SubmitHandler } from '@modular-forms/qwik'
import { formAction$, useForm, valiForm$ } from '@modular-forms/qwik'
import { email, minLength, object, string, type Input } from 'valibot'

export default component$(() => {
 const formSchema=object({
    email: string([minLength(1, 'Please enter your email.'), email('form.validation.emailInvalid')]),
    firstName: string([
      minLength(1, 'Please enter your password.'),
      minLength(8, 'Your password must have 8 characters or more.'),
    ]),
  })
  const validate = valiForm$(formSchema)
  type BootcampRegisterForm = Input<typeof formSchema>

  const handleSubmit: QRL<SubmitHandler<BootcampRegisterForm>> = $((values) => {
    // Runs on client
    console.log(values)
  })
  const [, { Form, Field }] = useForm<BootcampRegisterForm>({
    loader: { value: { firstName: '', email: '' } },
    // action: useFormAction(),
    validate,
  })

  return (
    <Form onSubmit$={handleSubmit}>
      <Field name="firstName">
        {(field, props) => <input required {...props} {...field} label="First name" type="text" />}
      </Field>
      <Field name="email">
        {(field, props) => <input required {...props} {...field} label="E-mail" type="email" />}
      </Field>
      <button type="submit">Login</button>
    </Form>
  )
});

@DevHusariaSolutions
Copy link
Author

Moving schema outside component with translation hooks gives inproper behaviour - error is not translated, only key of translation is returned

const t = inlineTranslate()

const formSchema = z.object({
  firstName: z.string().min(3, { message: t('form.validation.nameInvalid') }),
  email: z
    .string({ required_error: t('form.validation.emailRequired') })
    .email({ message: t('form.validation.emailInvalid') }),
})

export const RegisterBootcampForm = component$(() => {
  const useFormAction = formAction$<BootcampRegisterForm>((values) => {
    // TODO: ADD BACKEND ACTION
    console.log(values)
  }, zodForm$(formSchema))
  type BootcampRegisterForm = z.infer<typeof formSchema>

  const handleSubmit: QRL<SubmitHandler<BootcampRegisterForm>> = $((values) => {
    // Runs on client
    console.log(values)
  })
  const [, { Form, Field }] = useForm<BootcampRegisterForm>({
    loader: { value: { firstName: '', email: '' } },
    action: useFormAction(),
    validate: zodForm$(formSchema),
  })

@DevHusariaSolutions
Copy link
Author

DevHusariaSolutions commented Jan 3, 2024

And another test failed:

  const t = inlineTranslate()

  type BootcampRegisterForm = { firstName: string; email: string }

  const handleSubmit: QRL<SubmitHandler<BootcampRegisterForm>> = $((values) => {
    // Runs on client
    console.log(values)
  })
  const [, { Form, Field }] = useForm<BootcampRegisterForm>({
    loader: { value: { firstName: '', email: '' } },
  })

  return (
    <Form onSubmit$={handleSubmit}>
      <Field name="firstName" validate={minLength(3, t('form.validation.nameInvalid'))}>
  Resigning from using formSchema and passing only validate stuff Field component also prints untranslated error...

@fabian-hiller
Copy link
Owner

It only works for me if I put the schema inside zodForm$. Not just the variable that stores the schema. But this makes it harder to infer the input type of the schema.

@DevHusariaSolutions
Copy link
Author

Ok, but can we do something about that? Schema is just object, which should be composable inside component in case we would like to:

  • add translations messages
  • dynamically set fields or validation conditions
  • pass it to children

And in Qwik 1.3.1+ even wraping it as You proposed throws error.

@fabian-hiller
Copy link
Owner

I will investigate this issue but it will take time. I plan to rewrite Modular Forms in February. Unfortunately, I don't have a perfect solution for you at the moment. You can try to define the error messages globally in Zod with an error map. Alternatively, you can also try switching to Valibot. I plan to implement our i18n feature by the end of this week. This should allow you to define your schema globally.

@DevHusariaSolutions
Copy link
Author

For Valibot it was the same. No problem, currently I'm using this for landing page, which is not problematic to handle outside it (especially, that user shouldn't start typeing data in form controls before switching to another language first).

@fabian-hiller
Copy link
Owner

Have you tried Valibot's new i18n feature? https://valibot.dev/guides/introduction/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

2 participants