0

I'm working with yup and react-hook-forms to validate a user submission. I'm creating an application that sends text messages, emails, and push notifications. The user can specify where they would like to be contacted via a set of checkboxes. These 3 checkboxes update a single stateful object that looks like this by default:

  const [checkboxes, setCheckboxes] = useState({
    phone: false,
    email: false,
    push: false,
  });

I need to validate that at least one of these is changed to true before the form can be submitted and if not, I'd like to throw an error with a message. To that end I found the .test function of yup and am trying the following:

  fieldset: yup
    .object()
    .shape({
      phone: yup.bool(),
      email: yup.bool(),
      push: yup.bool(),
    })
    .required()
    .test(
      "comms-Selected",
      "Please specify at least one means to be contacted",
      (value) =>
        value.phone === true || value.email === true || value.push === true
    ),

I'm not sure about the syntax of this validator function and the yup documentation is making my head spin. I know that it's not working because I can submit the form with all fields unchecked. Can someone help me to understand how to properly write this custom validator?

TheFunk
  • 981
  • 11
  • 39
  • the schema looks good to me, how do you wire it up with your form? are you getting an error just validating an object (`{phone: false, email: false, push: false}`). – Jerryc Nov 10 '20 at 02:56
  • It's wired with a handleSubmit function which works for my other fields but not the custom validator. I'm wondering if I need to use an if statement instead of an expression on the last line and then an else statement to manually create and assign the error if none of the checkboxes evaluate to true. – TheFunk Nov 10 '20 at 04:24

2 Answers2

1

found this issue, modified to meet your needs https://github.com/jquense/yup/issues/72

let SignupSchema = yup.object().shape({
  firstName: yup.string().required(),
  age: yup.number().required().positive().integer(),
  // website: yup.string().url(),
  choice1: yup.boolean(),
  choice2: yup.boolean(),
  choice3: yup.boolean()
});

// extend the existing schema for the choice validation
SignupSchema = SignupSchema.test(
  // this test is added additional to any other (build-in) tests
  "choicesTest",
  null, 
  (obj) => {
    // only testing the checkboxes here
    if (obj.choice1 || obj.choice2 || obj.choice3) {
      return true; // everything is fine
    }

    return new yup.ValidationError("Check at least one ", null, "choices");
  }
);

HTML

<div>
  <label style={{ lineHeight: 1, padding: 0, margin: 0 }}>
    Check - Choice 1
    <input type="checkbox" name="choice1" ref={register} />
  </label>
  <label style={{ lineHeight: 1, padding: 0, margin: 0 }}>
    Check - Choice 2
    <input type="checkbox" name="choice2" ref={register} />
  </label>
  <label style={{ lineHeight: 1, padding: 0, margin: 0 }}>
    Check - Choice 3
    <input type="checkbox" name="choice3" ref={register} />
  </label>
  {errors.choices && <p>{errors.choices.message}</p>}
</div>
Aaron Saunders
  • 33,180
  • 5
  • 60
  • 80
0

Thank you for your responses and answers. I have found the problem. My syntax was good. It turns out in a drunken stupor I accidentally updated react-hook-form yesterday night to a newer version and with the newer version there is a second dependency and slightly different syntax for declaring your yup resolver. Lo and behold, adding the dependency and changing one line in the code caused my original code above to work. For anyone in the same boat, consult the react-hook-form documentation! Their integration with schema validators has changed ever so slightly!

Original line and dependencies for react-hook-form 5.x.x:

import { useForm } from "react-hook-form";
import * as yup from "yup";

  const { register, handleSubmit, setValue, errors } = useForm({
    validationSchema: ContactSchema, //name of your schema goes here
  });

Revised for react-hook-form 6.x.x:

import { useForm } from "react-hook-form";
import * as yup from "yup";
import { yupResolver } from "@hookform/resolvers/yup";

  const { register, handleSubmit, setValue, errors } = useForm({
    resolver: yupResolver(ContactSchema),
  }); 
TheFunk
  • 981
  • 11
  • 39