Проверить поле в Yup на основе нескольких значений связанных полей с помощью Yup.ref и .test

Я создал многоступенчатую форму в react: ^ 17.0.1, yup: ^ 0.29.3 и formik: ^ 2.2.3.

Я хочу проверить, что, когда пользователь вводит свой день рождения (dobD), он действителен на основе месяца рождения (dobM) и года рождения (dobY).

У меня есть 3 отдельных входа. dobM, dobD, dobY

Первая проверка dobD работает (т.е. пользователь может ввести только значение от 1 до 31), однако она не проверяет правильно, если это месяц с менее чем 31 днем ​​(например, июнь или сентябрь) ИЛИ если месяц февраль ( что всего 28 дней за исключением високосных лет).

Я попытался использовать Yup.ref для ссылки на поля года и месяца внутри проверки поля дня, однако, если я ввожу для месяца 04, пользователь все равно может ввести 31, что неверно (поскольку апрель (04) имеет только 30 дней).

Есть идеи, как это исправить? Спасибо!

Вот проверка в Yup, которую я сейчас использую:

  // Step 3: Date of Birth
  Yup.object().shape({
    dobM: Yup.string()
      .test(
        'dobM',
        'Invalid Month',
        value => {
          if (value < 1 || value > 12) {
            return false;
          }
          return true;
        }
      )
      .min(2, 'Invalid')
      .max(2, 'Invalid')
      .required('Required'),
    dobY: Yup.string()
      .test(
        'dobY',
        'Valid Year required',
        value => {
          const today = new Date();
          const adultYear = today.getFullYear() - 17;
          if (value < 1900 || value > adultYear) {
            return false;
          }
          return true;
        }
      )
      .min(4, 'Must be 4 digits')
      .max(4, 'Must be 4 digits')
      .required('Valid Year required'),
    dobD: Yup.string()
      .test(
        'dobD',
        'Invalid Day',
        value => {
          if (value < 1 || value > 31) {
            return false;
          }

          // Check months with less than 31 days - DOESNT WORK
          // 4. April
          // 6. June
          // 9. September
          // 11. November
          if ((Yup.ref('dobM') == 4 || Yup.ref('dobM') == 6 || Yup.ref('dobM') == 9 || Yup.ref('dobM') == 11) && value == 31) {
            return false;
          }

          // If February - DOESNT WORK
             if (Yup.ref('dobM') == 2) {
             const isLeapYear = Yup.ref('dobY') % 4 == 0 && (Yup.ref('dobY') % 100 != 0 || Yup.ref('dobY') % 400 == 0);

             if (day > 29 || (day == 29 && !isLeapYear)) {
               return false;
             }
           }

          return true;
        }
      )
      .min(2, 'Invalid')
      .max(2, 'Invalid')
      .required('Required'),  
  }), 

person Lauren Little    schedule 03.12.2020    source источник


Ответы (1)


Размещаю свое решение в надежде, что это поможет кому-то другому.

Я неправильно использовал Yup.ref (Yup.ref ('fieldname') - это объект, а не отдельное значение).

** Чтобы иметь возможность получить доступ к другому полю в Yup, я преобразовал из функции стрелки в обычную функцию в моем тесте, а затем мог получить доступ к значениям поля, используя

this.options.parent.FIELD_NAME

видно в этом примере:

function(day) {
          const month = this.options.parent.dobM;
          const year = this.options.parent.dobY;
 
         // check whatever you want with the value of month and year
}

Полная проверка DOB:

  // Step 3: Date of Birth
  Yup.object().shape({
    dobM: Yup.string()
      .matches(/^(0[1-9]|1[012])$/, 'Invalid Month')
      .test(
        'dobM',
        'Invalid Month',
        value => {
          if (value < 1 || value > 12) {
            return false;
          }
          return true;
        }
      )
      .min(2, 'Invalid')
      .max(2, 'Invalid')
      .required('Required'),
    dobY: Yup.string()
      .test(
        'dobY',
        'Valid Year required',
        value => {
          const today = new Date();
          const adultYear = today.getFullYear() - 17;
          if (value < 1900 || value > adultYear) {
            return false;
          }
          return true;
        }
      )
      .matches(/^[0-9]+$/, 'Must be only digits')
      .min(4, 'Must be 4 digits')
      .max(4, 'Must be 4 digits')
      .required('Valid Year required'),
    dobD: Yup.string()
      .test(
        'dobD',
        'Invalid Day',
        function(day) {
          const month = this.options.parent.dobM;
          const year = this.options.parent.dobY;
          // February
          if (month == 2) {
            const isLeapYear = year % 4 == 0 && (year % 100 != 0 || year % 400 == 0);

            if (day > 29 || (day == 29 && !isLeapYear)) {
              return false;
            }
          }
          return true;
        }
      )
      .test(
        'dobD',
        'Invalid Day',
        function(day) {
          const month = this.options.parent.dobM;
          // Check months with less than 31 days
          // 4. April
          // 6. June
          // 9. September
          // 11. November
          if ((month == 4 || month == 6 || month == 9 || month == 11) && day == 31) {
            return false;
          }
          return true;
        }
      )
      .test(
        'dobD',
        'Invalid Day',
        day => {
          if (day < 1 || day > 31) {
            return false;
          }
          return true;
        }
      )
      .matches(/^[0-9]+$/, 'Digits Only')
      .min(2, 'Invalid Day')
      .max(2, 'Invalid Day')
      .required('Required'),  
  }),

Примечание: для удобства чтения я переместил каждую проверку для dobD в свой собственный Yup .test (), однако это не требуется.

person Lauren Little    schedule 04.12.2020