Reputation: 11778
I have two fields itemlist
and itemlistUpload
I am using react-hook-forms
. I want the user to provide either one of the them. And one of them is required
How can i do the validation
import { useForm, Controller } from "react-hook-form";
import {
Col,
Row,
Form,
FormGroup,
InputGroup,
Input,
Container
} from "reactstrap";
export default function App() {
const onSubmit = (data) => {
console.log(data);
};
const { control, handleSubmit } = useForm();
return (
<Container>
<Form onSubmit={handleSubmit(onSubmit)}>
<Row className="m-3">
<Col>
<Controller
name="itemlist"
control={control}
render={({ field: { ref, ...field } }) => (
<Input
{...field}
type="textarea"
rows={10}
placeholder="itemlist"
required
innerRef={ref}
/>
)}
/>
</Col>
</Row>
<Row className="m-3">
<Col>
<FormGroup row className="mr-md-1">
<InputGroup className="mb-3">
<Controller
name="itemlist2"
control={control}
render={({ field: { ref, ...field } }) => (
<Input
{...field}
type="file"
required
innerRef={ref}
/>
)}
/>
</InputGroup>
</FormGroup>
</Col>
</Row>
</Form>
</Container>
);
}
Here is the codesandbox https://codesandbox.io/s/bitter-grass-erz7t
Upvotes: 8
Views: 10918
Reputation: 1583
The best way is to use validate function, the validate
function should return true
if field is valid, and false
otherwise, or you can return an error message. only Boolean true is considered as valid, so you need to be cautious when you are using this function. You do not need to validate both fields in this example.
import { useForm, Controller } from "react-hook-form";
import { Col, Row, Form, FormGroup, InputGroup, Input, Container } from "reactstrap";
export default function App() {
const onSubmit = (data) => {
console.log(data);
};
const { control, handleSubmit } = useForm();
return (
<Container>
<Form onSubmit={handleSubmit(onSubmit)}>
<Row className="m-3">
<Col>
<Controller
name="itemlist"
control={control}
rules={{
validate: (value, formValue) => {
// use this validation to check if one of the fields is filled
return !!value || !!formValue.itemlist2 || "one of itemlist or itemlist2 is required";
},
}}
render={({ field: { ref, ...field } }) => (
<Input {...field} type="textarea" rows={10} placeholder="itemlist" required innerRef={ref} />
)}
/>
</Col>
</Row>
<Row className="m-3">
<Col>
<FormGroup row className="mr-md-1">
<InputGroup className="mb-3">
<Controller
name="itemlist2"
control={control}
render={({ field: { ref, ...field } }) => <Input {...field} type="file" required innerRef={ref} />}
/>
</InputGroup>
</FormGroup>
</Col>
</Row>
</Form>
</Container>
);
}
Upvotes: 1
Reputation: 632
Remove the 'required' attribute from both inputs and validate the fields manually by using setError and clearErrors functions from useForm. (https://react-hook-form.com/api/useform/seterror, https://react-hook-form.com/api/useform/clearerrors)
Check if one of the fields have been filled out in when the form has been submitted, if not, set a new error and don't log the data. Then add logic to the inputs' onChange functions to clearErrors once data has been entered.
import "./styles.css";
import { useForm, Controller } from "react-hook-form";
import {
Col,
Row,
Form,
FormGroup,
InputGroup,
Input,
Container
} from "reactstrap";
export default function App() {
const onSubmit = (data) => {
if (!data.itemlist && !data.itemlist2) {
setError("neitherItemlist", {
type: "manual",
message: "You must fill out either itemlist or itemlist1"
});
return;
}
console.log(data);
};
const {
control,
handleSubmit,
setError,
formState: { errors },
clearErrors
} = useForm();
return (
<Container>
<Form onSubmit={handleSubmit(onSubmit)}>
<Row className="m-3">
<Col>
<Controller
name="itemlist"
control={control}
render={({ field: { ref, ...field } }) => (
<Input
{...field}
type="textarea"
rows={10}
placeholder="itemlist"
innerRef={ref}
onChange={(e) => {
field.onChange(e);
clearErrors("neitherItemlist");
}}
/>
)}
/>
</Col>
</Row>
<Row className="m-3">
<Col>
<FormGroup row className="mr-md-1">
<InputGroup className="mb-3">
<Controller
name="itemlist2"
control={control}
render={({ field: { ref, ...field } }) => (
<Input
{...field}
type="file"
innerRef={ref}
onChange={(e) => {
field.onChange(e);
clearErrors("neitherItemlist");
}}
/>
)}
/>
</InputGroup>
</FormGroup>
</Col>
</Row>
{errors.neitherItemlist && (
<p style={{ color: "red" }}>{errors.neitherItemlist.message}</p>
)}
<input type="submit" />
</Form>
</Container>
);
}
https://codesandbox.io/s/confident-brook-14zwj?file=/src/App.js:0-2208
Upvotes: 6