Formik: Why are empty strings mapped to undefined before validation?

Created on 2 Aug 2018  路  12Comments  路  Source: formium/formik

I'm wondering what the reason for this code is

https://github.com/jaredpalmer/formik/blob/955b6d3624630a92c7e840dc39b13e4f5612278f/src/Formik.tsx#L663-L668

I want to have an input which is either null (i.e. hidden) or a string but cannot be an empty string.

yup
    .string()
    .notOneOf([''], 'Required')
    .nullable()

This doesn't work if the field in question is at the top level of the form due to the coercing of '' to undefined which makes yup ignore the field if its value is empty. But what's even more unexpected is that it does work when the field is nested in a sub object since the coercion is not recursive.

I'm sure there's a good reason for this behaviour and I would like to understand it.

Medium Question stale

All 12 comments

I forgot why. @jquense is there a good way to do this in Yup land?

I was wondering why it was there as well. I'm guessing it's because an empty string in a form context is usually an empty or missing field, wereas to yup it's a value to validate.

Usually I'd handle this at the input level, converting empty strings to null, to keep those semantics local to the input component. There also a few ways to handle this in yup if you wanted like adding a custom transform(), there isn't a built in one tho, but maybe there should be

Ian (eonwhite) is on his honeymoon right now and I don't want to ping him. He wrote that part initially IIRC. He'll be back in a week or so.

@jaredpalmer @eonwhite do you have some progress with this issue guys? I'm stuck on it.

If i'm correct you trying to check that key is exist on values array. You need to replace values[key] !== '' with typeof values[key] !== 'undefined', but i'm not sure, because I don't know what structures contains in this arrays.

You are right, this does date back to the original proto-Formik code from spring '17! The reason as @jquense guessed, is to force Yup to skip validation on optional fields that are empty.

The fact that it does not apply this rule to sub-objects as @tamlyn noticed is, I think, an oversight and a bug. Whatever the behavior is, it should probably be consistent between top level or in sub-objects.

I could see an argument that this behavior is too magical altogether, and maybe we should consider a breaking change to remove it. But (beyond compatibility breakage) it would come at the cost of making some validations for optional fields harder to express, since it would force the user to explicitly check for the empty-string case in many situations.

For what @tamlyn is trying to do (conditionally validate a field depending on some other form state), there are some clearer ways to express this idea -- for example using Yup's when() to conditionally apply the required validation.

Hello, I ran into an issue related to this yesterday. I have a component <Payment /> that can have any number of child components of various types related to form fields. Something like:

<Payment>
  <FirstName />
  <LastName />
  <CreditCardNumber />
  <ExpirationDate />
</Payment>

The Yup schema makes heavy use of yup.lazy to ensure that the initialValues contains the field before trying to validate it. This code setting things to undefined is turning all the empty string values into undefined so that even though I'm setting the values to empty strings in initialValues the fields aren't getting validated until a value is entered. So even though all of these fields are required it is allowing an empty value for each of them since my schemas for the fields look something like:

// Should only validate the number if the creditCardNumber is present in initialValues of Formik
creditCardNumber: yup.lazy(value => {
  // This is my problem right here. The Formik code is setting all empty strings
  // to undefined so this wont work.
    if (value !== undefined) {
      return creditCardNumber // reference to the schema for the field
    }
    return yup.mixed().notRequired()
  })

So I think a workaround for my use case would be to nest all of these fields inside a sub-schema({ payment: { creditCardNumber}}, but I really don't like how ugly that makes the code for the react components. Thoughts?

work to cover this use-case more directly and broadly is being discussed here: https://github.com/jquense/yup/issues/298

Hola! So here's the deal, between open source and my day job and life and what not, I have a lot to manage, so I use a GitHub bot to automate a few things here and there. This particular GitHub bot is going to mark this as stale because it has not had recent activity for a while. It will be closed if no further activity occurs in a few days. Do not take this personally--seriously--this is a completely automated action. If this is a mistake, just make a comment, DM me, send a carrier pidgeon, or a smoke signal.

ProBot automatically closed this due to inactivity. Holler if this is a mistake, and we'll re-open it.

I am also facing the same problem! Does anyone have a solution?

I too came across a use-case where I need to use Yup.test for custom validation of a complex value and this seems to be a big problem. Any help is appreciated.

I had the same problem with Yup.string().defined() and Formik.

My current workaround is to use Yup.string().default('').defined(): Formik changes '' to undefined before passing in the value to Yup, Yup then changes undefined back to '' before validation.

Very ugly of course...

Was this page helpful?
0 / 5 - 0 ratings

Related issues

jaredpalmer picture jaredpalmer  路  3Comments

emartini picture emartini  路  3Comments

giulioambrogi picture giulioambrogi  路  3Comments

ancashoria picture ancashoria  路  3Comments

jaredpalmer picture jaredpalmer  路  3Comments