Не проверять нетронутые поля в Formik и Yup при отправке, если поле не пустое

У меня есть эта схема проверки для формы, созданной с использованием withFormik(), используемого в моем приложении React. Здесь validateJql() - моя настраиваемая функция проверки для yup

validationSchema: Yup.object().shape({
            rework: Yup.string().required("Rework query is required").validateJql(), 
            originalEstimate: Yup.string().required("Original Estimate query is required").validateJql()
        })

и мой компонент формы выглядит так:

const addSomeForm = (props) => {
    const {
        values,
        touched,
        errors,
        isSubmitting,
        handleChange,
        handleSubmit,
    } = props;

return (
        <form onSubmit={handleSubmit}>
             <div className="form-group">
                  <div>
                      <label htmlFor="name" className="col-form-label"><b>Rework Query:</b></label>
                      <textarea id="query.rework" rows="5" type="text" className="form-control" placeholder="Enter JQL with aggregate Function" value={values.query.rework} onChange={handleChange} required />
                       {errors.query && errors.query.rework && touched.query && <span className="alert label"> <strong>{errors.query.rework}</strong></span>}
                   </div>
             </div>
             <div className="form-group">
                 <div>
                      <label htmlFor="name" className="col-form-label"><b>Original Estimate:</b></label>
                       <textarea id="query.originalEstimate" rows="5" type="text" className="form-control" placeholder="Enter JQL with aggregate Function" value={values.query.originalEstimate} onChange={handleChange} required />
                       {errors.query && errors.query.originalEstimate && touched.query && <span className="alert label"> <strong>{errors.query.originalEstimate}</strong></span>}
                 </div>
             </div>
       </form>
    )

Теперь я хочу не запускать проверку при отправке формы, если поля rework и originalEstimate не затронуты и также не пусты. Как я могу добиться этого с помощью withFormik HOC или Yup? Я частично просмотрел Yup docs и Formik docs, но не смог найти что-то подходящее для моей проблемы.

Это происходит после однократной отправки формы и последующего редактирования для незначительных изменений в некоторых из этих нескольких полей. если имеется несколько полей и редактируются только некоторые, я не хочу запускать проверку для всех существующих полей.

Заранее спасибо.


person ShivaGaire    schedule 01.02.2019    source источник
comment
Вы когда-нибудь находили решение этой проблемы?   -  person douglasrcjames    schedule 02.07.2019
comment
Еще не нашел. Поделись со мной, когда найдешь   -  person ShivaGaire    schedule 02.07.2019
comment
Мой конкретный вариант использования был решен следующим образом: stackoverflow.com/questions/56844264/   -  person douglasrcjames    schedule 02.07.2019
comment
У меня такая же проблема ...   -  person Tom    schedule 26.08.2019


Ответы (2)


Это желаемое поведение по умолчанию, как указано в formik docs но я думаю, вы можете сделать следующее:

Вместо использования validationSchema используйте функцию validate.

Функция Validate будет работать так же, как и ваша validationSchema. Вам просто нужно программно использовать Yup из функции с mixed.validate

Таким образом, вы можете полностью контролировать все реквизиты в вашей форме. Вы также можете использовать getFieldMeta, чтобы получить касание и значение поля и использовать его при проверке. Или получите эти реквизиты из объекта touched в форме с помощью getIn

Что-то вроде:


// Some util functions
function mapYupErrorsToFormikErrors(err: { inner: any[] }) {
  return err.inner
    .filter((i: { path: any }) => !!i.path)
    .reduce(
      (curr: any, next: { path: any; errors: any[] }) => ({
        ...curr,
        [next.path]: next.errors[0],
      }),
      {},
    )
}

function validateSchema(values: object, schema: Schema<object>) {
  return schema
    .validate(values, {
      abortEarly: false,
      strict: false,
    })
    .then(() => {
      return {}
    })
    .catch(mapYupErrorsToFormikErrors)
}


// Your validation function, as you are using `withFormik` you will have the props present

function validateFoo(values, props) {
  const { touched, value } = props.getFieldMeta('fooFieldName') // (or props.form.getFieldmeta, not sure)

  const errors = validateSchema(values, yourYupSchema)

  if (!touched && !value && errors.fooFieldName) {
    delete errors.fooFieldName
  } 

  return errors  
}

Что ж, touched может не сработать для вашего варианта использования, потому что formik, вероятно, установит его в true при отправке, но у вас есть все реквизиты, и вы можете использовать что-то другое, например, пустое значение или какое-то другое свойство состояния, которое вы установили вручную. У вас там весь контроль.

person Diego Segura    schedule 02.06.2020

У меня была аналогичная проблема, я создал другое поле, в котором я установил значение при отображении экрана редактирования. Затем я сравниваю внутри тестовой функции, например:

originalField: yup.string().default(''),

field: yup.string().default('').required('Field is required.').test('is-test',
    'This is my test.',
    async (value, $field) => {
      if($field.parent.originalField !== '' && value === $field.parent.originalField) return true
      return await complexAsyncValidation(value)
    }

Не идеально, но определенно работает

person Edwin Joassart    schedule 11.03.2021