Santhosh
Santhosh

Reputation: 11778

react-hook-form: How to validate when either of two fileds are required

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

Answers (2)

Ako
Ako

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>
  );
}

Sandbox Exmaple

Upvotes: 1

coot3
coot3

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

Related Questions