Search code examples
reactjsfrontendformikyup

Conditional validation in Yup and formik and semantic-ui


I am new to Formik & Yup Validation. I have some fields depend on semantic-ui dropdown .When I click on a field a particular input field and a drop down will open. I cannot do the validation properly. I want when Facebook is selected these fields show validate not Instagram fields, when Instagram is selected only these fields show validation not Facebook fields.. here is the working sandbox link https://codesandbox.io/s/adoring-davinci-z4qlnw?file=/src/UserInfo.jsx My validation code is here..

export const ProfessionalValidation = yup.object().shape({
 category: yup.array().required('Category Name is required').nullable(),
 
 FBfollowers: yup.string().required('Atleast One Flatform is required').nullable(),
 Instafollowers: yup.string().required('Atleast One Flatform is required').nullable(),
 facebookLink: yup.string().required('This Field is required').nullable(),
 platform: yup.array().required('Atleast One Flatform is required').nullable(),
})

userinfo is here

import { ProfessionalValidation } from "./Validation";
import { ErrorMessage, Formik, Form, Field } from "formik";
import {
  ageGroup,
  categoryOptions,
  Platform,
  gender,
  followers,
  subscribers
} from "./Data";
import { Dropdown } from "semantic-ui-react";
import "./style.css";
import "./styles.css";

const UserInfo = () => {
  const [selectedOptions, setOptions] = useState([]);
  const [savedata, setSaveData] = useState([]);

  const defaultValue = {
    category: "",
    platform: "",
    facebookLink: "",
    InstaLink: "",
    Instafollowers: "",
    FBfollowers: "",
    subscribers: "",
    youtube: ""
  };

  return (
    <>
      
      <Formik
        initialValues={defaultValue}
        validationSchema={ProfessionalValidation}
        onSubmit={handleSubmit}
      >
        {({ values, setFieldValue }) => (
          <Form>
            <section className="form-styling my-4">
              <div className="container">
                <div className="input-box2">
                  <div>
                    <label htmlFor="category">Category*</label>

                    <Field
                      clearable
                      name={`category`}
                      fluid
                      multiple
                      search
                      selection
                      options={categoryOptions}
                      component={Dropdown}
                      placeholder="Select Category"
                      onChange={(_, { value }) =>
                        setFieldValue("category", value)
                      }
                    />
                    <span style={{ color: "red" }}>
                      <ErrorMessage name="category" />
                    </span>
                  </div>

                  <div>
                    <label htmlFor="platform">Platform*</label>
                    <Field
                      clearable
                      name={`platform`}
                      fluid
                      multiple
                      search
                      selection
                      options={Platform}
                      placeholder="Select Platform"
                      component={Dropdown}
                      onChange={(_, { value }) => {
                        const onDropChange = () => {
                          setOptions(value);
                          setSaveData(selectedOptions);
                          setFieldValue("platform", value);
                        };
                        onDropChange();
                      }}

                      //onChange= {onDropChange}
                    />
                    <span style={{ color: "red" }}>
                      <ErrorMessage name="platform" />
                    </span>
                    <span className="mt-3 d-block">Select at least 1</span>
                  </div>
                </div>
                {/* all selected platform show in this div */}

                <div className="platform-box">
                  <div>
                    {selectedOptions.find((word) => word === "Facebook") &&
                    values.platform.find((word) => word === "Facebook") ? (
                      <div>
                        <div className="platform-details">
                          <div>
                            <h5>Facebook</h5>
                          </div>
                          <div>
                            <Field
                              type="text"
                              name="facebookLink"
                              placeholder="Account Link"
                              //onBlur={(value) => setFieldValue("facebookLink",value.currentTarget)}
                            />
                            <span className="text-danger">
                              <ErrorMessage name="facebookLink" />
                            </span>
                          </div>
                          <div>
                            <Field
                              className="label ui selection fluid dropdown"
                              clearable
                              name={`FBfollowers`}
                              fluid
                              search
                              selection
                              options={followers}
                              component={Dropdown}
                              placeholder="Select followers"
                              onChange={(_, { value }) =>
                                setFieldValue("FBfollowers", value)
                              }
                            />
                            <span className="text-danger">
                              <ErrorMessage name="FBfollowers" />
                            </span>
                          </div>
                        </div>

                        <span>Verify the Followers in 2-3 Business Days</span>
                      </div>
                    ) : null}

                    {selectedOptions.find((word) => word === "Instagram") ? (
                      <div>
                        <div className="platform-details">
                          <div>
                            <h5>Instagram</h5>
                          </div>
                          <div>
                            <Field
                              type="text"
                              name="InstaLink"
                              placeholder="Account Link"
                            />
                          </div>
                          <div>
                            <Field
                              className="label ui selection fluid dropdown"
                              clearable
                              name={`Instafollowers`}
                              fluid
                              search
                              selection
                              options={followers}
                              component={Dropdown}
                              placeholder="Select followers"
                              onChange={(_, { value }) =>
                                setFieldValue("Instafollowers", value)
                              }
                            />
                            <span style={{ color: "red" }}>
                              <ErrorMessage name="Instafollowers" />
                            </span>
                          </div>
                        </div>

                        <span>Verify the Followers in 2-3 Business Days</span>
                      </div>
                    ) : null}
                  </div>
                </div>
              </div>
              {/* container end  */}
            </section>
            {/* additional info */}

            <section className="additional-Info ">
              <div className="container">
                <div className="main-box"></div>

                <div className="text-start my-5">
                  <button type="submit" className="border-0">
                    <span className="btn-form btn btn-info">Continue</span>
                  </button>
                </div>
              </div>
            </section>
          </Form>
        )}
      </Formik>
    </>
  );
};

export default UserInfo;

Solution

  • Yup provides .when api for mixed validation. You can use it like below.

    FBfollowers: yup
        .string()
        .when("platform", {
          is: (val) => val?.includes("Facebook"),
          then: yup.string().required("Atleast One Flatform is required"),
          otherwise: yup.string()
        })
        .nullable(),
    

    Since the value for platform field is an array, I've used .includes to check whether user has selected specific platform. If this returns true then the field will be made mandatory, otherwise it will be non-mandatory.

    Here is updated code for validation.jsx file.

    import * as yup from "yup";
    
    export const ProfessionalValidation = yup.object().shape({
      category: yup.array().required("Category Name is required").nullable(),
    
      FBfollowers: yup
        .string()
        .when("platform", {
          is: (val) => val?.includes("Facebook"),
          then: yup.string().required("Atleast One Flatform is required"),
          otherwise: yup.string()
        })
        .nullable(),
      Instafollowers: yup
        .string()
        .when("platform", {
          is: (val) => val?.includes("Instagram"),
          then: yup.string().required("Atleast One Flatform is required"),
          otherwise: yup.string()
        })
        .nullable(),
      facebookLink: yup
        .string()
        .when("platform", {
          is: (val) => val?.includes("Facebook"),
          then: yup.string().required("This field is required"),
          otherwise: yup.string()
        })
        .nullable(),
      platform: yup.array().min(1, "Atleast one Field is required").nullable()
    });
    
    

    And here is the updated working code sandbox.

    Here is more on the .when api of Yup.

    Hope this helps.