Yup: How to match two fields?

Created on 21 Mar 2016  路  9Comments  路  Source: jquense/yup

is there something similar to the joi ref function?

email: joi.string().email().required(),
confirmEmail: joi.string().valid(joi.ref('email')).required()

Most helpful comment

you are using an arrow function which has a bound 'this' use a normal function ()

All 9 comments

Not immediately obvious but you can use the test function

Yup.mixed().test('match', 'Emails do not match', function (email) {
  return email === this.options.context.confirmEmail
})

I made a convenience method like this:

Yup.match = function (key, message, func) {
  message = message || 'Values do not match';
  func = func || function (value) {
    return value === this.options.context[key];
  }

  return Yup.mixed().test('match', message, func);
};

var schema = { 
  email: Yup.string().email(),
  confirmEmail: Yup.match('email', 'Emails do not match')
}

@reohjs has it correct, there is no Joi ref equivalent (yet!), but inside of the test function the context (this) of the function contains some helpful properties.

Above uses context which is actually not the most correct, since context isn't always the "parent" object. there is however, a property called parent which is the object containing the current thing you are testing.

here is an example making sure a date is after another date

date().test('date-test', 'Must be after the client ready date', function (value) {
   let { clientReadyDate } = this.parent;
   return value == null || dates.gte(value, clientReadyDate, 'day')
}),

FYI I'd be happy to take a PR adding proper Ref support here, it actually shouldn't be too tough.

when i implement either suggestion, this is undefined.

const schema = yup.object.shape({
  email: yup.string().email('Invalid email address').required('Email is required'),
  confirmEmail: yup.string().test('email-match', 'Emails do not match', (value) => {
    const { email } = this.parent;
    return email === value;
  })
});

i feel like i'm missing something here?

you are using an arrow function which has a bound 'this' use a normal function ()

I have a related question on this. When transforming one field, can I get the value of another field?
Take the example in above issue, can I do something like this:

email: yup.string().email('Invalid email address').required('Email is required'),
confirmEmail: yup.string().transform( function() {
    //can I get this.email here?
})

This issue ranks high on Google so if someone is trying to figure out this, go and check the solution here: https://github.com/jquense/yup/issues/97#issuecomment-306547261

@ArtixZ you can use yup.ref('email') to get email value

Stumbled into this issue today. Solved it by evaluating the values of this.parent was pretty straightforward, so thought I'd share in case someone else runs into this.

import { mixed, object, string } from 'yup';

let errorMsg = "Please enter a password";

export let resetPasswordSchema = object().shape({
  password: string().required(errorMsg),
  passwordConfirmation: mixed().test(
    "match",
    "Passwords do not match", // your error message
    function () {
      return this.parent.password === this.parent.passwordConfirmation;
    }
  )
});

i feel like i'm missing something here?

this.parent is valid only in not arrow functions

Was this page helpful?
0 / 5 - 0 ratings