2
votes

I'm trying to learn how to use Formik and Yup to validate an input(text) form field. I've follwed the standard approach by Jared Palmer and it worked great straight out of the box.

When it comes to doing something a little more component driven, I'm having a tough time achieveing the same level of valdation and I just can't work out where I'm going wrong?

Yup doesn't seem to be able to identify my Form Model and won't validate the input field as required ...

I'm thinking that I've actually messed up the Initial Values or I'm not providing them in the right shape that Yup is looking for, but any assitance here would be amazing, this is driving mad...

I have an example sandbox up and running here > >

https://codesandbox.io/s/building-multi-step-form-with-formik-yup-vjzpk

Form Model (components/CheckoutPage/FormModel/checkoutFormModel.js):

export default {
  formId: "checkoutForm",
  formField: {
    nestedObj: {
      firstName: {
        name: "firstName",
        label: "First name*",
        requiredErrorMsg: "First name is required"
      }
    }
  }
};

Initial Values (components/CheckoutPage/FormModel/initialValues.js):

import checkoutFormModel from "./checkoutFormModel";
const {
  formField: {
    nestedObj: { firstName }
  }
} = checkoutFormModel;

export default {
  nestedObj: {
    [firstName.name]: ""
  }
};

Yup Validation Schema (components/CheckoutPage/FormModel/validationSchema.js):

import * as Yup from "yup";
import checkoutFormModel from "./checkoutFormModel";
const {
  formField: {
    nestedObj: { firstName }
  }
} = checkoutFormModel;

export default [
  Yup.object().shape({
    nestedObj: Yup.object().shape({
      [firstName.name]: Yup.string().required(`${firstName.requiredErrorMsg}`)
    })
  })
];

Address Form which combines Yup and Formik (components/CheckoutPage/Forms/AddressForm.js):

import React from "react";
import { Grid } from "@material-ui/core";
import { InputField } from "../../FormFields";

export default function AddressForm(props) {
  const {
    formField: {
      nestedObj: { firstName }
    }
  } = props;
  return (
    <React.Fragment>
      <Grid container spacing={3}>
        <Grid item xs={12} sm={6}>
          <InputField name={firstName.name} label={firstName.label} fullWidth />
        </Grid>
      </Grid>
    </React.Fragment>
  );
}
1

1 Answers

1
votes

What happens where is that your yup validation will validate an object like

{
    nestedObj: {
        [firstName.name]: '' // Validation will get here
    }
}

But when you pass to your input name={firstName.name} your input is going to be like

{
    [firstName.name]: ''
}

So you are missing the validation because you added nestedObj in the yup validation

OR

You forgot to add nestedObj to the firstName.name.

So what you can do is change your validation schema to

Yup.object().shape({
  [firstName.name]: Yup.string().required(`${firstName.requiredErrorMsg}`)
})

OR

Pass to the input, the name nestedObj

<InputField name={`nestedObj.${firstName.name}`} label={firstName.label} fullWidth />

You can pass it as a prop or just hardcode string, you choose.