Formik: Formik + Yup | How to render split views for Edit/Create Form

Created on 28 Mar 2019  路  1Comment  路  Source: formium/formik

My question revolves around a particular scenario I am currently facing. I am using the withFormik H.O.C, along with Yup, to handle various cases in my forms, such as submitting, errorHandling, and a few more depending on the situation.

Usually, my form situation involves a Create and an Edit Mode.
onCreate => Pass the defaultvalues and call the POST Method, from my services.
onEdit => Populate the values with the current Item Values from the Server, and call the PUT Method from the services.

Example


  const validationSchema = Yup.object().shape({
    username: Yup.string('Provide a Username').required('Username is Required'),
    email: Yup.string().email('Provide a Valid email Address'),
    password: Yup.string('Provide a Password').required('Password is required'),
    confirmPassword: Yup.string('Provide your password again')
      .required('Password Confirmation is Required')
      .oneOf([Yup.ref('password')], 'Passwords do not match'),
  });

  const EnchancedCreateUserForm = withFormik({
    mapPropsToValues: ({
      user = {
        username: '',
        email: '',
        password: '',
        confirmPassword: '',
      }
    }) => ({ ...user }),

    validationSchema,

    handleSubmit: (values, { props, setSubmitting }) => {
      const { doSubmit, onSave, inEditMode } = props;

      const saveUser = inEditMode ? updateUser : createUser;
      return doSubmit(saveUser, values)
        .then(() => {
          setSubmitting(false);
          onSave();
        })
        .catch(() => {
          setSubmitting(false);
        });
    },

    displayName: 'AddEditUser'
  })(AddEditUser);

That is actually been working great for me, since my Create and Edit Form are the same. And here lay my 2 problems.

Current Situation

My current form implementation has 2 views. One unified one on Create with those 4 fields, and on Edit, I have 2 forms. One for passwordChange and one for infoChange. Which makes me face the following problems.

  1. I would need 3 FormValidationSchemas(CREATE, EDIT-INFO, EDIT-PASSWORD). Which I am not sure formik even supports.
  2. How exactly, should I handle the rest of the functionality, onSubmit, ErrorMessage for both field error and statusError?

If you could actually help me out figure a way of attack it would be great.

I read the validationSchema can be passed a function that returns a validationSchema, so I did this, but it is not working:

  const validationFullSchema = Yup.object().shape({
    username: Yup.string('Provide a Username').required('Username is Required'),
    email: Yup.string().email('Provide a Valid email Address'),
    password: Yup.string('Provide a Password').required('Password is required'),
    confirmPassword: Yup.string('Provide your password again')
      .required('Password Confirmation is Required')
      .oneOf([Yup.ref('password')], 'Passwords do not match'),
  });

  const validationEditSchema = Yup.object().shape({
    username: Yup.string('Provide a Username').required('Username is Required'),
    email: Yup.string().email('Provide a Valid email Address'),
  });

  validationSchema: validationSchemaFn(),
  // Which throws an error
  // Failed to load app. Error: Cannot read property 'props' of undefined

I probably am doing something wrong, but I put it here just in case.

My Opinion on the matter

  • Create 2 Form Components(PasswordFormComponent, InfoFormComponent), and wrap each one with the H.O.C, allowing them access to the withFormik independantly.
  • For CreateForm, convert it into a container Component, that renders both of those components.
  • For Edit instead of calling the whole form, which is currently what is happening, call for each situation the specific component.

What do you of my proposed solution? If you like it, could you please make it better or help with some code samples, espacially in the multiple validationSchemas issue. Thank you!!

Formik Question

Most helpful comment

Hey! Thanks for the write up. How best to structure Create vs. Edit is a decision that comes up in pretty much every single application. Unfortunately, the answer is: it depends. The good news is that your reasoning about this problem is 100% on track. In general, I like to to keep things that are similar (i.e. likely to be changed at the same time) as close as possible and separate things that are different (i.e. unlikely to be changed at the same time). Some observations/guesses...

  • You are pretty much never going to make changes the update password form after you build it.
  • You will very likely make lots of changes to your signup form
  • Your signup form could differ from your "user info" form with respect to it's visuals and/or it could require fewer fields.

Cognizant of the above, I suggest actually making 3 forms. While yes, you can use the function version of validation schema, I find that this tends to get messy when you have more than 2 versions of your form. Since you are breaking out edit user info and edit password, I would thus split each of these up into totally separate <Formik>'s with their own validationSchema's (although you could in theory share the parts of the inner object). FWIW in our apps, this decision is very clear cut because we make a special update password endpoint (that's different from update user) that takes the old password and the new one (and confirms that they are indeed different values).

I hope that helps.

Side note: Very very clever to use Yup.oneOf() for matching. In the past, we've just written out our own Yup.equalTo as described in https://github.com/jquense/yup/issues/97

>All comments

Hey! Thanks for the write up. How best to structure Create vs. Edit is a decision that comes up in pretty much every single application. Unfortunately, the answer is: it depends. The good news is that your reasoning about this problem is 100% on track. In general, I like to to keep things that are similar (i.e. likely to be changed at the same time) as close as possible and separate things that are different (i.e. unlikely to be changed at the same time). Some observations/guesses...

  • You are pretty much never going to make changes the update password form after you build it.
  • You will very likely make lots of changes to your signup form
  • Your signup form could differ from your "user info" form with respect to it's visuals and/or it could require fewer fields.

Cognizant of the above, I suggest actually making 3 forms. While yes, you can use the function version of validation schema, I find that this tends to get messy when you have more than 2 versions of your form. Since you are breaking out edit user info and edit password, I would thus split each of these up into totally separate <Formik>'s with their own validationSchema's (although you could in theory share the parts of the inner object). FWIW in our apps, this decision is very clear cut because we make a special update password endpoint (that's different from update user) that takes the old password and the new one (and confirms that they are indeed different values).

I hope that helps.

Side note: Very very clever to use Yup.oneOf() for matching. In the past, we've just written out our own Yup.equalTo as described in https://github.com/jquense/yup/issues/97

Was this page helpful?
0 / 5 - 0 ratings

Related issues

jaredpalmer picture jaredpalmer  路  3Comments

sibelius picture sibelius  路  3Comments

Jungwoo-An picture Jungwoo-An  路  3Comments

najisawas picture najisawas  路  3Comments

jaredpalmer picture jaredpalmer  路  3Comments