admin管理员组

文章数量:1392068

So this is fairly strange and I can't understand where it's ing from.

I have a signup WS (in Node.js using Sales.js) where the minimum required age is 18 years old, the validation is done by Yup.

This is my yup schema:

const yup = require('yup');
const moment = require('moment');

const birthdate = yup.date()
  .typeError('INVALID_DATE')
  .min(moment().subtract(115, 'years'), 'MIN_AGE')
  .max(moment().endOf('day').subtract(18, 'years'), 'MAX_AGE');

module.exports = {
  birthdate
};

So this is fairly strange and I can't understand where it's ing from.

I have a signup WS (in Node.js using Sales.js) where the minimum required age is 18 years old, the validation is done by Yup.

This is my yup schema:

const yup = require('yup');
const moment = require('moment');

const birthdate = yup.date()
  .typeError('INVALID_DATE')
  .min(moment().subtract(115, 'years'), 'MIN_AGE')
  .max(moment().endOf('day').subtract(18, 'years'), 'MAX_AGE');

module.exports = {
  birthdate
};

As you can see from the example underneath, when I put today's date, it is paring it to 2002-07-31 while it's supposed to be pared with moment().endOf('day').subtract(18, 'years') which would be 2002-08-12

Note that 2002-07-31 is the date in which I built the project. So if I repile it now, I will no longer have that problem for today. If I retest tomorrow, it will pare it with today’s date! I have no idea how is this possible or how to fix it.

This is the error from yup:

"errors": [{
  "field": "birthdate",
  "code": "E_MAX_AGE_BIRTHDATE",
  "params": {
    "path": "birthdate",
    "value": "2002-08-12T10:00:00.000Z",
    "originalValue": "2002-08-12T10:00:00.000Z",
    "max": "2002-07-31T21:59:59.999Z"
  }
}]

Any ideas? Versions used: moment 2.24.0 ; yup 0.29.2

Share Improve this question edited Aug 13, 2020 at 15:50 Hassen Ch. asked Aug 12, 2020 at 17:32 Hassen Ch.Hassen Ch. 1,7731 gold badge20 silver badges32 bronze badges
Add a ment  | 

2 Answers 2

Reset to default 3

For anyone wanting a simpler way to have a dynamic date (e.g. now) that is evaluated at the moment of validation (e.g. not the time at build date): use yup.lazy().

The below example will check the min date is later than the max date (and vice versa), with a dynamic max date that is freshly generated on each validation attempt.

import { date, lazy, object, ref } from 'yup'

function getMinDate() {
    return new Date(2000, 1, 1)
}

function getMaxDate() {
    return new Date()
}

const schema = object({
    minDate: date()
        .min(getMinDate(), `Min start date is ${getMinDate()}`)
        .max(ref('maxDate'), 'Min date must be earlier than the max date'),
    maxDate: lazy(() => date()
        .min(ref('minDate'), 'Max date must be later than min date')
        .max(getMaxDate(), `Max start date is ${getMaxDate()}`)
  )
})

Okay so I found the solution.

As a matter of a fact, Yup will store the date you initially gave and pile it. It will no longer execute moment().endOf('day').subtract(18, 'years') each time you validate a date.

For this, you have to use a test method, not min nor max.

I have created an extension method to yup.date as following:

/**
 * This function is used to format the error like date.min does
 */
function customValidationError(errorMessage, value, path, extraData) {
  const error = new yup.ValidationError(errorMessage,
    value,
    path);
  error.params = {
    path: path,
    value: value,
    originalValue: value,
    ...extraData
  };
  return error;
}

/**
 * Extension method to yup.date
 * You should pass a function that will be executed each time you want to check again the current date.
 * @name yup.dynamicMaxDate
 * @global yup.dynamicMaxDate
 */
yup.addMethod(yup.date, 'dynamicMaxDate', function(path, errorMessage = 'MAX_DATE', maxDateFunction) {
  return this.test(path, errorMessage,
    (value) => {
      const maxDate = maxDateFunction();
      return new Promise((resolve, reject) => {
        const error = customValidationError(errorMessage, value, path, {
          max: maxDate
        });
        value && moment(value).isAfter(maxDate) ?
          reject(error) :
          resolve(true);
      });
    });
});

/**
 * Extension method to yup.date to check if date is before a given date
 * You should pass a function that will be executed each time you want to check again the current date.
 * @name yup.dynamicMinDate
 * @global yup.dynamicMinDate
 */
yup.addMethod(yup.date, 'dynamicMinDate', function(path, errorMessage = 'MIN_DATE', minDateFunction) {
  return this.test(path, errorMessage,
    (value) => {
      const minDate = minDateFunction();
      return new Promise((resolve, reject) => {
        const error = customValidationError(errorMessage, value, path, {
          min: minDate
        });
        value && moment(value).isBefore(minDate) ?
          reject(error) :
          resolve(true);
      });
    });
});

And to use those methods:

const birthdate = yup.date()
  .typeError('INVALID_DATE')
  // Note tham I'm passing a function to be executed when validating date
  .dynamicMinDate('birthdate', 'MIN_AGE', () => {
    return moment().startOf('day').subtract(115, 'years').toDate();
  })
  .dynamicMaxDate('birthdate', 'MAX_AGE', () => {
    return moment().endOf('day').subtract(18, 'years').toDate();
  });

本文标签: javascriptYup compares min max date with build date instead of current dateStack Overflow