Hi i have a form with 8 fields.
- Name
- isWorking (checkbox)
- Company Name
- Company Type
- Company Number
- Fav Car (dropdown)
- 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:-
-
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.
-
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
Looking at the docs, the value passed to the callback in
when
is an array of values, not just the value itself:From docs:
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:
to:
The alternative syntax you could use is this:
Please change your schema.js file into this code.
In short, in
companyName: yup.string().when('isWorking', (val) => { ...
if you get value of "val" using
console.log(val)
, you will see[true]
NOTtrue
This is same in
otherCar: yup.string().when('favCar', (val) => {...
.