yup-phone: notRequired() with empty string causes validation to fail

There is no way to make a field optional but validate when not an empty string.

Yup.string().phone(true, false, 'Phone not valid').notRequired()

About this issue

  • Original URL
  • State: open
  • Created 4 years ago
  • Reactions: 23
  • Comments: 15 (5 by maintainers)

Most upvoted comments

Or actually a better workaround without creating additional values like ‘isPhoneBlank’ is to add new method to yup where we can conditionally validate different schemas if value is blank:

Yup.addMethod(Yup.string, 'validatePhone', function () {
  return this.test('test-phone', "This phone number doesn't seem to look valid", value => {
    if (value) return this.phone().isValidSync(value)
    return true
  })
})

Or simply use .test method in schema without adding new method:

Yup.string().test('test-phone', "This phone number doesn't seem to look valid", value => {
    if (value) return this.phone().isValidSync(value)
    return true
  })

To add here from @kmacoder

const phoneSchema = yup.string().phone('US', true);

const validationSchema = yup.object({
   ...otherValidations,
   phone: yup.string().test('test-phone', 'Invalid format', (value) => {
      if (value) return phoneSchema.isValidSync(value);
      return true;
  }),
});

Or actually a better workaround without creating additional values like ‘isPhoneBlank’ is to add new method to yup where we can conditionally validate different schemas if value is blank:

Yup.addMethod(Yup.string, 'validatePhone', function () {
  return this.test('test-phone', "This phone number doesn't seem to look valid", value => {
    if (value) return this.phone().isValidSync(value)
    return true
  })
})

Or simply use .test method in schema without adding new method:

Yup.string().test('test-phone', "This phone number doesn't seem to look valid", value => {
    if (value) return this.phone().isValidSync(value)
    return true
  })

@dan003400 I think this works as a workaround:

const schema = Yup.object().shape({
  phone: Yup.string().when("isPhoneBlank", {
    is: false,
    then: Yup.string().phone(),
    otherwise: Yup.string(),
  }),
});

Using .when() referencing a sibling boolean key/value pair let’s you check if the phone string is blank, and only use yup-phone if it isn’t.

On the off chance you’re using Formik doing this quick check whenever validations happen seems to be working alright:

onChange={(e) => {
  if (values.phone && values.phone.length > 0) {
    setValues(
      { ...values, isPhoneBlank: false },
      false
    );
  } else {
    setValues(
      { ...values, isPhoneBlank: true },
      false
    );
  }
  handleChange(e);
}}

This was how I fixed empty field validation.

const [phone, setPhone] = useState()

function validatePhone() {
        if (phone) {
            return yup.string().phone(null, true, "Invalid Phone Number")
        } else {
            return yup.string().ensure()
        }
}

const validationSchema = yup.object({
   ...otherValidations,
   phone: validatePhone(),
})

<PhoneInputWithCountry
      className="form-control"
      defaultCountry="US"
      name="phone"
      id="phone"
      value={phone}
      onChange={setPhone}
      control={control}
  />

According to yup string.ensure() documentation

string.ensure(): Schema
Transforms undefined and null values to an empty string along with setting the default to an empty string.

I hope this works for someone. All thanks to @abhisekp. Happy coding.

Hi folks, I really need this change for a project, Can I be of any help to make this PR merged asap ? (already looked at @nightness changes and it seems fine to me !)

Thanks for your PR @nightness

@abhisekp Just did the PR.

@nightness Would you like to file a PR with the given code?