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

Zod optional, nullable or nullish don't work when having previous validations #196

Closed
wladpaiva opened this issue Jun 24, 2023 · 12 comments
Closed
Labels
help wanted Extra attention is needed

Comments

@wladpaiva
Copy link

I was following along with epic stack and decided to try making the password field on login page optional

export const loginFormSchema = z.object({
  username: usernameSchema,
  password: z
    .string()
    .min(6, {message: 'Password is too short'})
    .max(100, {message: 'Password is too long'})
    .optional(),
  redirectTo: z.string().optional(),
  remember: checkboxSchema(),
})

I'm not sure if this is a problem with the @conform-to/zod only or it extends to the @conform-to/react but it somehow just ignores the optional in favor of the previous rules.

I can easily see some situations where nullish, nullable and optional are important.

As a workaround I had to make it like this

  password: z.string().optional().or(z
    .string()
    .min(6, {message: 'Password is too short'})
    .max(100, {message: 'Password is too long'})),
@edmundhung
Copy link
Owner

Hi @wladiston,

Thank you for bringing up the issue. This is because zod consider a field to be missing only when the value is undefined, but the web form sends an empty string when the input is empty.

Unfortunately there is not much Conform can help at the moment. I have tried stripping empty string to match the zod behaviour in the previous version. But it causes another issue with refinement not running on the object schema as well.

References:

@edmundhung
Copy link
Owner

I am re-considering stripping empty string on the zod integration to better align with how zod works and I would like to hear more thoughts on this from the community.

@wladpaiva
Copy link
Author

I guess the main problem here is how to interpret the empty string. I'd say that the best scenario I've seen is when empty strings are interpreted as null. It makes sense for me that if a user clears the field and submit the form, to just save the null on the database instead of saving an empty string

@edmundhung
Copy link
Owner

v0.7.4 introduced a new option to strip empty value on parse. It will be really helpful if some of you could try enabling this option and let me know if there is any issue. This option would likely be the default on v0.8.

@edmundhung edmundhung added the help wanted Extra attention is needed label Jul 17, 2023
nicholaschiang added a commit to nicholaschiang/dolce that referenced this issue Jul 25, 2023
This patch refactors the sign up page to create a new profile settings
page that allows users to preview what their consumer reviews will look
like and update their username, name, email, and password accordingly.

Eventually, I should also add a profile picture upload input.

This patch takes advantage of Conform's new `skipEmptyValues` option to
optionally accept the `password` field in this settings page.

Ref: https://github.com/edmundhung/conform/releases/tag/v0.7.4
Ref: edmundhung/conform#224
Ref: edmundhung/conform#196
nicholaschiang added a commit to nicholaschiang/dolce that referenced this issue Jul 25, 2023
This patch refactors the sign up page to create a new profile settings
page that allows users to preview what their consumer reviews will look
like and update their username, name, email, and password accordingly.

Eventually, I should also add a profile picture upload input.

This patch takes advantage of Conform's new `skipEmptyValues` option to
optionally accept the `password` field in this settings page.

Ref: https://github.com/edmundhung/conform/releases/tag/v0.7.4
Ref: edmundhung/conform#224
Ref: edmundhung/conform#196
@edmundhung
Copy link
Owner

Update: The stripEmptyValue will be removed as v0.8 will support this through schema introspection instead. This will also enable automatic type coercion.

@edmundhung
Copy link
Owner

Resolved on v0.8.0.

@milhamm
Copy link

milhamm commented Sep 30, 2023

Is there a way to not strip empty value? @edmundhung

I have a case where I want to update a text input field to an empty value. However, I can't do it since the empty values are stripped

@edmundhung
Copy link
Owner

@milhamm Can you share a bit more why you need to have it as empty string? IMO, stripping empty string is necessary to align with how zod works. How about using a transform to cast it to empty string if the value is undefined? Or simply do value ?? ''

@aaronschwartz
Copy link

aaronschwartz commented Oct 13, 2023

@edmundhung I also have a case where I would like to submit empty strings. Our backend API has fields that accept empty strings, but cannot accept null values. It feels strange that there is no way I can set up the Zod schema to make this work with Conform.

To me it feels like there is a difference between:

An empty input -> Should submit an empty string (as web forms currently do). You can always use the .min(1) if you don't want to accept the empty string. I believe this is how it works if you're using Zod in other libraries like react-hook-form.

Removing the input from the page (or setting the input to disabled) -> Should not submit the field and you can use .optional Zod schema to determine if you would like to accept the entire form or not.

I feel like the transform should be the other way around, and we should be casting empty strings to undefined if that is how we want to interpret empty strings in our database.

@edmundhung
Copy link
Owner

edmundhung commented Oct 13, 2023

The major concern here is how we can utilise zod optional correctly. If we do not strip out empty string, zod will consider the field to be present and continue running the rest of the validation.

Imagine a zod schema like this:
z.string().email().optional()

Zod will report the field to have an invalid email even though it is empty.

There are also other impacts if you tried to inspect all the errors.

Imagine the same schema above but it becomes required this time. If the field is empty, zod will only report the required error. But if you use min check, it will run both the min length and email check.

These are just some of the examples. But my gut feeling right now is that we should align with how zod works to ensure proper support of all its features.

@aaronschwartz
Copy link

aaronschwartz commented Oct 13, 2023

I do see the concern.

I don't think setting email to optional is the correct schema for this case. I believe the way Zod says this should be handled (taken from the current documentation):

Optional string validation:

To validate an optional form input, you can union the desired string validation with an empty string literal.

This example validates an input that is optional but needs to contain a valid URL:

const optionalUrl = z.union([z.string().url().nullish(), z.literal("")]);

I don't think this schema is supported right now with Conform.

I think it is up to the user to transform it into a null if that is how their db wants it, but lots of people might not store it like that).

@aaronschwartz
Copy link

@edmundhung I know you're probably answering more questions than usual, but I was wondering if you had an opinion on how to handle Zod's recommendation for optional string validation suggested above?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
help wanted Extra attention is needed
Projects
None yet
Development

No branches or pull requests

4 participants