Search code examples
reactjsreact-hook-formyup

If field1 is dependent on field2 how can we update the error message of field1 even if field2 changes in yup and react-hook-forms


I am using react-hook-forms along with yup. I have two input fields one is select and another one is input field. Lets say the first input says the type of bank and another input number is account number. I am validating like this based on the type of bank the number of digits in account number changes. Since, I am using yup I am using yup.when() for dependence validation. After we submit the form data the validation happen in onChange. So, my main problem is when validation is in onChange and if I change account number based on input change the error message is changing but if I have a account number and when I change bank now the error validation message for account number is not updating. thanks in advance.

I am attaching code sandBox link https://codesandbox.io/s/pensive-waterfall-3o4n3q?file=/src/App.js

I am also adding the code apart from code sandbox.

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

const schema = yup.object({
  account: yup.object({
    bank: yup.string().required("*required"),
    accountNumber: yup
      .number()
      .required("*required")
      .typeError("Must be a number")
      .when("bank", (bank, schema) => {
        // console.log(schema);
        console.log(bank);
        if (bank === "SBI") {
          return schema
            .min(10000000000, "SBI bank has 11 digits")
            .max(99999999999, "SBI bank has 11 digits");
        } else if (bank === "HDFC") {
          return schema
            .min(10000000000000, "HDFC bank has 14 digits")
            .max(99999999999999, "HDFC bank has 14 digits");
        } else {
          return schema
            .min(100000000000000, "Andhra bank has 15 digits")
            .max(999999999999999, "Andhra bank has 15 digits");
        }
      })
  })
});

export default function App() {
  const {
    handleSubmit,
    register,
    formState: { errors }
  } = useForm({
    resolver: yupResolver(schema),
    mode: "onChange",
    reValidateMode: "onChange"
  });
  const submit = (data) => {
    console.log("hello");
    console.log(data);
  };
  return (
    <div className="App">
      <form onSubmit={handleSubmit(submit)}>
        <label>
          Bank Name
          <select {...register("account.bank")}>
            <option>Andhra Bank</option>
            <option>SBI</option>
            <option>HDFC</option>
          </select>
          <p>{errors.account?.bank?.message}</p>
        </label>
        <label>
          Account Number
          <input
            type="text"
            placeholder="Account Number"
            {...register("account.accountNumber")}
          />
          <p>{errors?.account?.accountNumber?.message}</p>
          {/* <p>{errors.account?.message}</p> */}
        </label>
        <input type="submit" />
      </form>
    </div>
  );
}

My problem when validation happen if one bank is set and start editing the account number it successfully showing the error message. let me say if bank is set to SBI and I start editing account number and typing number the error message is going to be "SBI bank has 11 digits" until I give 11 numbers now in between I remembered bank is not SBI so I changed the bank name to Andhra Bank then according to my requirement the error message of account number should change to "Andhra bank has 15 digits" but it remain unchanged as "SBI bank has 11 digits" until I made atleast one change in account number


Solution

  • I found a way to achieve this by having a custom onChange method like this

    <select {...register('financialInformation.account.bank',{
                     onChange : (e) => {
                      setValue('account.bank',e.target.value);
                      trigger();                }
                    })}>
                <option>Andhra Bank</option>
                <option>SBI</option>
                <option>HDFC</option>
              </select>
    

    and also i used when instead of test full solution is below and I am also attaching sandbox link https://codesandbox.io/s/infallible-browser-b2dkri?file=/src/App.js

    Full code is

    import React from "react";
    import * as yup from "yup";
    import { yupResolver } from "@hookform/resolvers/yup";
    import { useForm } from "react-hook-form";
    
    const schema = yup.object({
      account: yup.object({
        bank: yup.string().required("*required"),
        accountNumber: yup
          .number()
          .required("*required")
          .typeError("Must be a number")
          .when('bank',(bank,schema)=>{
            console.log(bank);
            if(bank === 'SBI'){
                return schema.min(10000000000,'SBI bank has 11 digits').max(99999999999,'SBI bank has 11 digits')
            }
            else  if(bank === 'HDFC'){
                return schema.min(10000000000000,'HDFC bank has 14 digits').max(99999999999999,'HDFC bank has 14 digits')
            }
            else{
                return schema.min(100000000000000,'Andhra bank has 15 digits').max(999999999999999,'Andhra bank has 15 digits')
            }
        })
      })
    });
    
    export default function App() {
      const {
        handleSubmit,
        register,
        trigger, 
        setValue,
        formState: { errors }
      } = useForm({
        resolver: yupResolver(schema),
        mode: "onChange",
        reValidateMode: "onChange"
      });
      const submit = (data) => {
        console.log("hello");
        console.log(data);
      };
      return (
        <div className="App">
          <form onSubmit={handleSubmit(submit)}>
            <label>
              Bank Name
              <select {...register('financialInformation.account.bank',{
                     onChange : (e) => {
                      setValue('account.bank',e.target.value);
                      trigger();                }
                    })}>
                <option>Andhra Bank</option>
                <option>SBI</option>
                <option>HDFC</option>
              </select>
            </label>
            <br />
            <label>
              Account Number
              <input
                type="text"
                placeholder="Account Number"
                {...register("account.accountNumber")}
              />
              <p>{errors?.account?.accountNumber?.message}</p>
              {/* <p>{errors.account?.message}</p> */}
            </label>
            <input type="submit" />
          </form>
        </div>
      );
    }