Formik: [Q] Custom errors with yup validation

Created on 9 Nov 2017  路  4Comments  路  Source: formium/formik

Right now I consider it a question, which can alter to potential proposal.

Although there could be potentially more scenarios, I think this one explains it well. Here is a minimal example: https://codesandbox.io/s/3k0lqyq3qp.

When we leave all fields empty and submit the form all errors coming from yup will be shown. And error which belongs to specific input disappears when onChange is called. Then we write something to both inputs, so they pass validation, and submit the form. Now we get some error from API and set those errors accordingly (line 24). Problem happens when we start editing one input, then validation is run, which returns no errors (they pass yup) and custom errors are overwritten (https://github.com/jaredpalmer/formik/blob/master/src/formik.tsx#L345), which makes overall behaviour inconsistent.

Do you have an idea how to handle this? Would it make sense to merge those errors somehow?

Thanks for your time.

Most helpful comment

Formik has a status and setStatus which was basically built for this kind of use case. Instead of "merging" errors, just place them on status. Then you can just conditionally display them:

https://codesandbox.io/s/yqj45jwy0v

import React from 'react';
import { render } from 'react-dom';

import { Formik } from 'formik';
import yup from 'yup';

const styles = {
  fontFamily: 'sans-serif',
  textAlign: 'center',
};

const schema = yup.object().shape({
  email: yup.string().required('Email required'),
  pswrd: yup.string().required('Password required'),
});

const App = () => (
  <div style={styles}>
    <Formik
      validationSchema={schema}
      initialValues={{ email: '', pswrd: '' }}
      onSubmit={(values, actions) => {
        // setting API errors
        actions.setStatus({
          email: 'This is email already exists.',
          pswrd: 'This is incorrect',
        });
      }}
      render={({ handleSubmit, handleChange, handleBlur, values, errors, status }) => (
        <form onSubmit={handleSubmit}>
          <input
            type="text"
            name="email"
            value={values['email']}
            onChange={handleChange}
            onBlur={handleBlur}
          />
          <input
            type="text"
            name="pswrd"
            value={values['pswrd']}
            onChange={handleChange}
            onBlur={handleBlur}
          />
          <button type="submit">Submit</button>

          {status && status.email ? (
            <div>Error: {status.email}</div>
          ) : (
            errors.email && <div>Error: {errors.email}</div>
          )}

          {status && status.pswrd ? (
            <div>Error: {status.pswrd}</div>
          ) : (
            errors.pswrd && <div>Error: {errors.pswrd}</div>
          )}
        </form>
      )}
    />
  </div>
);

render(<App />, document.getElementById('root'));

Fun fact:status was initially called error (singular) and setError in early versions of formik because my idea was to use it for api / top level error responses.

All 4 comments

Formik has a status and setStatus which was basically built for this kind of use case. Instead of "merging" errors, just place them on status. Then you can just conditionally display them:

https://codesandbox.io/s/yqj45jwy0v

import React from 'react';
import { render } from 'react-dom';

import { Formik } from 'formik';
import yup from 'yup';

const styles = {
  fontFamily: 'sans-serif',
  textAlign: 'center',
};

const schema = yup.object().shape({
  email: yup.string().required('Email required'),
  pswrd: yup.string().required('Password required'),
});

const App = () => (
  <div style={styles}>
    <Formik
      validationSchema={schema}
      initialValues={{ email: '', pswrd: '' }}
      onSubmit={(values, actions) => {
        // setting API errors
        actions.setStatus({
          email: 'This is email already exists.',
          pswrd: 'This is incorrect',
        });
      }}
      render={({ handleSubmit, handleChange, handleBlur, values, errors, status }) => (
        <form onSubmit={handleSubmit}>
          <input
            type="text"
            name="email"
            value={values['email']}
            onChange={handleChange}
            onBlur={handleBlur}
          />
          <input
            type="text"
            name="pswrd"
            value={values['pswrd']}
            onChange={handleChange}
            onBlur={handleBlur}
          />
          <button type="submit">Submit</button>

          {status && status.email ? (
            <div>Error: {status.email}</div>
          ) : (
            errors.email && <div>Error: {errors.email}</div>
          )}

          {status && status.pswrd ? (
            <div>Error: {status.pswrd}</div>
          ) : (
            errors.pswrd && <div>Error: {errors.pswrd}</div>
          )}
        </form>
      )}
    />
  </div>
);

render(<App />, document.getElementById('root'));

Fun fact:status was initially called error (singular) and setError in early versions of formik because my idea was to use it for api / top level error responses.

That is exactly what I am looking for! Thank you @jaredpalmer.
Feedback: for some reason, even if I went through the API table of contents and source code couple of times, I couldn't associate it with API errors 馃. Maybe we should add it to the guides section?

Submit a PR?

Will do 馃憤

Was this page helpful?
0 / 5 - 0 ratings

Related issues

green-pickle picture green-pickle  路  3Comments

jeffbski picture jeffbski  路  3Comments

emartini picture emartini  路  3Comments

outaTiME picture outaTiME  路  3Comments

pmonty picture pmonty  路  3Comments