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

Matching fields example (ie. Passwords) #90

Closed
mwickett opened this Issue Jul 25, 2017 · 18 comments

Comments

Projects
None yet
@mwickett

mwickett commented Jul 25, 2017

I'm struggling with getting a Yup validation working to ensure two fields match (in this case, password and password confirm).

    validationSchema: Yup.object().shape({
      password: Yup.string()
        .required('Password is required'),
      passwordConfirm: Yup.mixed().test('match', 'Passwords do not match', function (password) {
        return password === this.parent.passwordConfirm
      }).required('Password confirm is required')
    }),

I'm new to Formik & Yup (and relatively new to JS generally). Really appreciate any pointers.

@eonwhite

This comment has been minimized.

Collaborator

eonwhite commented Jul 25, 2017

Yup doesn't make this common usecase as easy as it should. Here's how I've gotten this to work (a slight modification of code in jquense/yup#97)

function equalTo(ref: any, msg: any) {
  return Yup.mixed().test({
    name: 'equalTo',
    exclusive: false,
    message: msg || '${path} must be the same as ${reference}',
    params: {
      reference: ref.path,
    },
    test: function(value: any) {
      return value === this.resolve(ref);
    },
  });
}
Yup.addMethod(Yup.string, 'equalTo', equalTo);

...

then in your validationSchema:

    passwordConfirm: Yup.string().equalTo(Yup.ref('password'), 'Passwords must match').required('Required'),
@mwickett

This comment has been minimized.

mwickett commented Jul 25, 2017

Thanks so much for this. I see how it's more complicated than I had originally thought, although this all makes sense. Appreciate you taking the time.

@mwickett mwickett closed this Jul 25, 2017

@vuhrmeister

This comment has been minimized.

vuhrmeister commented Jan 2, 2018

For me that is not working. Did anything regarding refs change?

@eonwhite I'm using your code, but I don't get the link. value is the actual value of the prop the test is running on. But this.resolve(ref) returns a StringSchema. So this comparison doesn't work.

I already searched for that issue but I didn't find any working solution to get the actual value of the ref.

*edit: I just saw this issue is posted for formik, so probably not the best place to answer if anything changed. But maybe someone has an idea though. (I came from jquense/yup#97)

@jquense

This comment has been minimized.

Contributor

jquense commented Jan 2, 2018

FYI folks this has gotten easier in the most recent version of yup. oneOf and notOneOf` now support refs

validationSchema: Yup.object({
  password: Yup.string().required('Password is required'),
  passwordConfirm: Yup.string()
     .oneOf([Yup.ref('password'), null])
     .required('Password confirm is required')
})
``
@vuhrmeister

This comment has been minimized.

vuhrmeister commented Jan 2, 2018

@jquense In 0.23.0? Doesn't work for me with .oneOf([Yup.ref('password')]). Also ${values} in message string just outputs [object Object]. The complete message is

newPasswordRepeat must be one of the following values: [object Object]

@FahdW

This comment has been minimized.

FahdW commented Jan 11, 2018

@jquense I found that the validation is incorrectly showing passwords that do in fact match as an error.
@vuhrmeister Make sure to write an error for it yup.string().oneOf([yup.ref('password'), null], "Passwords don't match") I also have an issue where it is not validating properly

@vuhrmeister

This comment has been minimized.

vuhrmeister commented Jan 11, 2018

@FahdW I have a custom error set. I just posted the minimal implementation.

@FahdW

This comment has been minimized.

FahdW commented Jan 11, 2018

@vuhrmeister Yeah the oneOf is not working i had to add my own method to get it to work

@jquense

This comment has been minimized.

Contributor

jquense commented Jan 11, 2018

looks like a bug, 'ill take a look

@lednhatkhanh

This comment has been minimized.

lednhatkhanh commented Jan 12, 2018

@jquense Doesn't work for my either, please take a look

@arthurdenner arthurdenner referenced this issue Jan 13, 2018

Merged

[WIP] Feature - Welcome Screen #138

2 of 3 tasks complete
@rareslupascu

This comment has been minimized.

rareslupascu commented Jan 28, 2018

tried mixed().oneOf ... string().oneOf ... nothing seems to work to match 2 fields :(

@rareslupascu

This comment has been minimized.

rareslupascu commented Jan 28, 2018

works with yup@0.24.0

@janzenz

This comment has been minimized.

janzenz commented May 26, 2018

oneOf's error message doesn't seem to make sense. Instead of confirming the 2 fields match, instead it gives me this error:

confirm_password must be one of the following values: , Ref(password)

Following @eonwhite solution is more correct.

@tushar-singh

This comment has been minimized.

tushar-singh commented May 28, 2018

@janzenz just specify custom error message

.oneOf([ref('password')], 'Passwords do not match')
@fahadakhan96

This comment has been minimized.

fahadakhan96 commented Aug 22, 2018

This doesn't work if I want to allow the password field to be empty.

password: Yup.lazy(
                    value =>
                      !value
                        ? Yup.string()
                        : Yup.string()
                            .min(6, 'Password must be at least 6 characters')
                            .required('Password is required'),
                  ),
confirmPassword: Yup.string().oneOf(
                    [Yup.ref('password')],
                    'Passwords do not match',
                  ),

The schema returns valid if password is not empty and confirmPassword is empty

@whatifif

This comment has been minimized.

whatifif commented Sep 17, 2018

I found that there is no 'equalTo' method in yup. This is a convenient method needed by everyone.
yup needs to include this 'equalTo' method as a basic one.

yup.addMethod(yup.mixed, 'equalTo', function(ref, message) {
    const msg = message || '${path} should match ${ref.path}';
    return this.test('equalTo', msg, function (value) {
      let refValue = this.resolve(ref);
      return !refValue || !value || value === refValue;
    })
})
@logistus

This comment has been minimized.

logistus commented Oct 27, 2018

I used manually triggering validation.

Added validate attribute to the password confirmation Field:

...
<Field type="password" name="password" id="password" />
<Field type="password" name="password_confirm" id="password_confirm" validate={validatePassword} />
...

and validatePassword function:

const validatePassword = (password) => {
  let error
  if (!password) {
    error = "Confirm password"
  }
  else if (password !== document.getElementById("password").value) {
    error = "Passwords do not match"
  }
  return error
}

@zakangelle zakangelle referenced this issue Nov 30, 2018

Merged

[yup]: Add resolve type to TestContext #30961

7 of 7 tasks complete
@telmotrooper

This comment has been minimized.

telmotrooper commented Dec 5, 2018

I just wanted to point out that if you want to display a custom error message based on @jquense 's answer, you'd do it like this:

validationSchema: Yup.object({
  password: Yup.string().required('Password is required'),
  passwordConfirm: Yup.string()
     .oneOf([Yup.ref('password'), null], "Passwords must match")
     .required('Password confirm is required')
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment