React Formik + Yup, onChange touch the field

Lucian Tarna picture Lucian Tarna · Sep 10, 2018 · Viewed 15.5k times · Source

I would like to conditionally display errors in my form.

The way formik works is that if you change one field all validations are ran and all errors returned even thought you changed just one.

I would like to display the error only if the field was TOUCHED and I would like a field to be TOUCHED onChange. The first change to the field should make it touched.

At the moment formik is touching fields just on submit. How would I be able to touch it onChange?

This is my current form:

const optionsForSelect = (collection) => {
  return collection.map(item => ({
    value: item.id,
    label: item.name
  }))
}

const validationSchema = yup.object().shape({
  length: yup
    .number()
    .min(1, 'Length should be a positive non-zero integer')
    .required(),
  frame_rate: yup
    .string()
    .required()
})

class SpecificationsForm extends React.PureComponent {
  render() {
    const {
      values,
      handleChange,
      handleInputChange,
      handleSelectChange,
      handleBlur,
      errors,
      touched
    } = this.props;

    const debouncedHandleChange = debounce(handleChange, 200)

    console.log(errors)
    console.log('TOUCHED')
    console.log(touched)
    return (
      <div className="panel panel-default specifications-panel" id="js-turbosquid-product-specifications-panel">
        <div className="panel-heading">
          <a href="#" className="js-more-info" data-toggle="collapse" data-target="#specifications-panel-instructions" tabIndex="-1">
            Specifications
            <i className="fa fa-question-circle" />
          </a>
        </div>

        <div className="panel-body panel-collapse collapse in" id="specification-panel-body">
          <div className="panel-body-container">
            <div id="specifications-panel-instructions" className="panel-instructions collapse" />

            <div className="row">
              <div className="col-xs-6">

                <PanelInputField 
                  label='Length'
                  value={ values.length }
                  onChange={ (e) => handleInputChange(e, debouncedHandleChange) }
                  formName='turbosquid_product_form_length'
                  fieldName='length'
                />

                <div className="form-field-error">{errors.length ? errors.length : "No Error"}</div>

                <PanelSelectField
                  label='Frame Rate'
                  value={ values.frame_rate }
                  onChange={ ({value}) => handleSelectChange('frame_rate', value) } 
                  formName='turbosquid_product_form_frame_rate'
                  fieldName='frame_rate'
                  options={ optionsForSelect(frameRateDropdownData) }
                  searchable={ false }
                  clearable={ false }
                />
              </div>

              <div className="col-xs-6">

                <PanelCheckBox
                  label='Biped'
                  checked={ values.biped }
                  onChange={ (e) => handleInputChange(e, debouncedHandleChange) }
                  fieldName='biped'
                  formName='turbosquid_product_form_biped'
                />

                <PanelCheckBox
                  label='Loopable'
                  checked={ values.loopable }
                  onChange={ (e) => handleInputChange(e, debouncedHandleChange) }
                  fieldName='loopable'
                  formName='turbosquid_product_form_loopable'
                />
              </div>
            </div>
          </div>
        </div>
      </div>
    )
  }
}

const ProductSpecificationsMotionCapturePanel = withFormik({
  validationSchema,
  enableReinitialize: true,
  mapPropsToValues: (props) => (props),
  handleInputChange: (props) => (props.handleInputChange),
  handleSelectChange: (props) => (props.handleSelectChange),
})(SpecificationsForm)

export default ProductSpecificationsMotionCapturePanel

Answer

Mudiaga Ejenavi picture Mudiaga Ejenavi · Oct 11, 2019

To touch a Formik field onChange, you can do this:

<Formik
initialValues={initialValues}
onSubmit={(values) => {
    //submit form
}}>
{({ setFieldTouched, handleChange }) => {
    return (
        <Form>
            <Field
                name="type"
                onChange={e => {
                    setFieldTouched('type');
                    handleChange(e);
                }} />
        </Form>
    )
}}