fabian-hiller / valibot

The modular and type safe schema library for validating structural data 🤖

Home Page:https://valibot.dev

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

`<select>` custom validation inside a `variant` schema

devatina11yb opened this issue · comments

Let’s say there’s a <select> element inside a form and other form fields are displayed according to the selected option, the default selected option is empty but validation must ensure there’s a selected value when submitting.

I’ve tried implementing this using a variant schema like this:

const schema = variant("type", [
  object({
    type: literal("")
  }, [custom((input) => input.type !== "", "Please select an option")]),
  object({
    type: literal("foo"),
    // ...
  }),
  object({
    type: literal("bar"),
    // ...
  }),
], /* also tried custom validation here with the same result */);

The custom validation function does get executed but the error message never reaches the form object, so I can’t use getError(form, "type") to display it. Is it the expected behavior?

This schema does seem to work as expected:

const schema = variant("type", [
  object({
    type: literal("foo"),
    // ...
  }),
  object({
    type: literal("bar"),
    // ...
  }),
], "Please select an option")

But then I can’t use {getValue(form, "type") !== "" ? <>...</> : undefined} without TypeScript complaining that "" doesn’t match "foo" | "bar".

Maybe there’s a better way avoiding this issue?

Please try the following schema and let me know if it works.

const schema = variant('type', [
  object({ type: literal('') }, [
    forward(
      custom((input) => input.type !== '', 'Please select an option'),
      ['type']
    ),
  ]),
  object({
    type: literal('foo'),
    // ...
  }),
  object({
    type: literal('bar'),
    // ...
  }),
]);

Please try the following schema and let me know if it works.

const schema = variant('type', [
  object({ type: literal('') }, [
    forward(
      custom((input) => input.type !== '', 'Please select an option'),
      ['type']
    ),
  ]),
  object({
    type: literal('foo'),
    // ...
  }),
  object({
    type: literal('bar'),
    // ...
  }),
]);

Thank you, it solved my issue.
Would you please explain why forwarding is needed?

This might also work. But the variant error cannot be associated with a specific field. Instead, it may be available via form.response. That's why I used forward in the preview schema I sent you to forward the issue to the type field.

const schema = variant("type", [
  object({
    type: literal("foo"),
    // ...
  }),
  object({
    type: literal("bar"),
    // ...
  }),
], "Please select an option")

This might also work. But the variant error cannot be associated with a specific field. Instead, it may be available via form.response. That's why I used forward in the preview schema I sent you to forward the issue to the type field.

const schema = variant("type", [
  object({
    type: literal("foo"),
    // ...
  }),
  object({
    type: literal("bar"),
    // ...
  }),
], "Please select an option")

Makes sense, thank you again for your help with this.