skip to Main Content

Hi i have a form with 8 fields.

  1. Name
  2. Email
  3. isWorking (checkbox)
  4. Company Name
  5. Company Type
  6. Company Number
  7. Fav Car (dropdown)
  8. Other Car

if isWorking is checked then Company (Name, Type, Number) fields will get visible and all 3 will be required fields else they will stay hidden and they will be optional field.

In fav car dropdown if other option is selected then Other Car input field will be visible and it will become required field and user will type their fav brand car else it will be optional field and other car field will be hidden.

How to write yup validation for Company(Name, Type, Number) fields based on isWorking field is checked and Other Car if Fav car is selected as other?

Problem:-

  1. Form should be submitted only if Fav Car is selected to Other and Other Car field contains a value instead it is submitting the form without displaying error msg for Other Car field.

  2. isWorking is optional field so if user doesn’t check isWorking checkbox then also form should get submitted but form is not getting submitted.

schema.js

import * as yup from 'yup';

const schema = yup.object({
  name: yup.string().required('Name is required'),
  email: yup.string().required('Email is required').email(),
  isWorking: yup.boolean(),
  favCar: yup.string().required('Select your fav brand car'),
  otherCar: yup.string().when('favCar', (val) => {
    if(val === 'other') {
      return yup.string().required('Please type your fav brand');
    } else {
      return yup.string().notRequired();
    }
  })
  companyName: yup.string().when("isWorking", (val) => {
    if (val) {
      return yup.string().required("Please type your company name");
    } else {
      return yup.string().notRequired();
    }
  }),
  companyType: yup.string().when("isWorking", (val) => {
    if (val) {
      return yup.string().required("Please select your company type!");
    } else {
      return yup.string().notRequired();
    }
  }),
  companyNumber: yup.string().when("isWorking", (val) => {
    if (val) {
      return yup.string().required("Please type your company number!");
    } else {
      return yup.string().notRequired();
    }
  }),
})
export default schema;

Form.js

import { Button, Row, Col, Form, Container } from "react-bootstrap";
import { useForm } from "react-hook-form";
import { yupResolver } from "@hookform/resolvers/yup";
import schema from "./schema";

export default function FormStatus() {

const {
    register,
    handleSubmit,
    reset,
    watch,
    formState: { errors },
  } = useForm({
    defaultValues: {
      name: '',
      email: '',
      isWorking: false,
      companyName: '',
      companyType: '',
      companyNumber: ''
    },
    resolver: yupResolver(schema),
  });

  let isUserWorking = watch("isWorking");
  let isOtherBrand = watch('favCar');

  const submitStatus = (ev) => {
    reset();
    console.log(ev);
  };

  return (
    <Form onSubmit={handleSubmit(submitStatus)}>
    <Container>
      <Row className="my-5">
        <Col
          sm={12}
          md={4}
        >
          <Form.Group>
              <Form.Label>Name</Form.Label>
              <Form.Control
                type="text"
                placeholder="Enter your name"
                {...register("name")}
              />
              <Form.Text className="text-danger">
                {errors.name?.message}
              </Form.Text>
            </Form.Group>
        </Col>
      </Row>
      <Row className="my-5">
        <Col
          sm={12}
          md={4}
        >
          <Form.Group>
              <Form.Label>Email</Form.Label>
              <Form.Control
                type="email"
                placeholder="Enter your email"
                {...register("email")}
              />
              <Form.Text className="text-danger">
                {errors.email?.message}
              </Form.Text>
            </Form.Group>
        </Col>
      </Row>
      <Row className="my-5">
          <Col
            sm={12}
            md={12}
          >
            <Form.Group>
              <Form.Check
                id="Are you Working?"
                size="lg"
                label="Are you Working?"
                {...register("isWorking")}
              />
            </Form.Group>
          </Col>
        </Row>
        {isUserWorking && (
          <Row>
            <Col
              sm={12}
              md={4}
            >
              <Form.Group>
                <Form.Label>Company Name</Form.Label>
                <Form.Control
                  placeholder="Please type your company name"
                  {...register("companyName")}
                />
                <Form.Text className="text-danger">
                  {errors.companyName?.message}
                </Form.Text>
              </Form.Group>
            </Col>
            <Col
              sm={12}
              md={4}
            >
              <Form.Group>
                <Form.Label>Company Type</Form.Label>
                <Form.Select {...register("companyType")}>
                  <option value="">--Select--</option>
                  <option value="public">Public</option>
                  <option value="private">Private</option>
                  <option value="other">Other</option>
                </Form.Select>
                <Form.Text className="text-danger">
                  {errors.companyType?.message}
                </Form.Text>
              </Form.Group>
            </Col>
            <Col
              sm={12}
              md={4}
            >
              <Form.Group>
                <Form.Label>Company Number</Form.Label>
                <Form.Control
                  type="number"
                  placeholder="Please type your company number"
                  {...register("companyNumber")}
                />
                <Form.Text className="text-danger">
                  {errors.companyNumber?.message}
                </Form.Text>
              </Form.Group>
            </Col>
          </Row>
        )}
      <Row>
          <Col
            md={6}
            sm={12}
          >
            <Form.Group>
              <Form.Label>Fav Car</Form.Label>
              <Form.Select {...register("favCar")}>
                <option value="">--Select Brand--</option>
                <option value="audi">Audi</option>
                <option value="bmw">BMW</option>
                <option value="bugati">Bugati</option>
                <option value="other">Other</option>
              </Form.Select>
              <Form.Text className="text-danger">
                {errors.favCar?.message}
              </Form.Text>
            </Form.Group>
          </Col>
        </Row>
        {isOtherBrand === "other" && (
          <Row className="my-5">
            <Col
              md={6}
              sm={12}
            >
              <Form.Group>
                <Form.Label>Other Car</Form.Label>
                <Form.Control
                  placeholder="Please type other car"
                  {...register("otherCar")}
                />
                <Form.Text className="text-danger">
                  {errors.otherCar?.message}
                </Form.Text>
              </Form.Group>
            </Col>
          </Row>
        )}
      <Row>
        <Col>
          <Button>Submit</Button>
        </Col>
      </Row>
    </Container>
    </Form>
  )
}

2

Answers


  1. Looking at the docs, the value passed to the callback in when is an array of values, not just the value itself:

    From docs:

    let schema = object({
      isBig: boolean(),
      count: number()
        .when('$other', ([other], schema) => <-- NOTE THE ARRAY DESTRUCTUING SYNTAX
          other === 4 ? schema.max(6) : schema,
        ),
    });
    

    It looks like your schemas don’t do this, they just assume that val is the value, but you should write it as [val] here:

    Change:

    companyNumber: yup.string().when("isWorking", (val) => {
    

    to:

    companyNumber: yup.string().when("isWorking", ([val]) => {
    

    The alternative syntax you could use is this:

    companyNumber: yup.string().when(
       "isWorking",
       (isWorking) => !!isWorking,
       then: (schema) => { ... },
       otherwise: (schema) { ... }
    
    Login or Signup to reply.
  2. Please change your schema.js file into this code.

    
    import * as yup from 'yup';
    
    const schema = yup.object({
        name: yup.string().required('Name is required'),
        email: yup.string().required('Email is required').email(),
        isWorking: yup.boolean(),
        favCar: yup.string().required('Select your fav brand car'),
        otherCar: yup.string().when('favCar', (val) => {
            if (val[0] === 'other') {
                return yup.string().required('Please type your fav brand');
            } else {
                return yup.string().notRequired();
            }
        }),
        companyName: yup.string().when("isWorking", (val) => {
            if (val[0]) {
                return yup.string().required("Please type your company name");
            } else {
                return yup.string().notRequired();
            }
        }),
        companyType: yup.string().when("isWorking", (val) => {
            if (val[0]) {
                return yup.string().required("Please select your company type!");
            } else {
                return yup.string().notRequired();
            }
        }),
        companyNumber: yup.string().when("isWorking", (val) => {
            if (val[0]) {
                return yup.string().required("Please type your company number!");
            } else {
                return yup.string().notRequired();
            }
        }),
    })
    export default schema;
    
    

    In short, in companyName: yup.string().when('isWorking', (val) => { ...
    if you get value of "val" using console.log(val), you will see [true] NOT true

    This is same in otherCar: yup.string().when('favCar', (val) => {... .

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search