I am evaluating react-hook-form for my application.
I am trying to find out a way to send dynamic values to custom validation function in react-hook-form.
We are using a library which in turn uses MUI, hence we have to use Controller component from react-hook-form.
I want to create a common validation rules file with common functions which I will be using in multiple forms. To achieve that I need to pass some values to the functions defined in validate option.
For instance for minMaxRule validation I need to define a common function which will accept min and max as parameters. I can see the types file of react-hook-form for validate will have a callback only with the value of that field. Is there any other way to achieve this ?
Form Component
import React, { BaseSyntheticEvent } from 'react';
import { Controller, useForm } from 'react-hook-form';
import { ruleSet } from '../../utils/validation/rules';
import { Validate, FieldValues } from 'react-hook-form';
export const ReactHookFormSample = (): JSX.Element => {
const { handleSubmit, control, formState: { errors }, getValues, register } = useForm({
mode: "onChange"
});
/**
* Call back on successful submit of form with form values
* @param data
* @param e
*/
const onSubmit = (data: any, e: BaseSyntheticEvent) => {
console.log('hook form', data);
}
/**
* Callback when form is submitted with errors
* @param errors
* @param e
*/
const one rror = (errors: any, e: BaseSyntheticEvent) => {
console.log('When errors form', errors);
}
const getError = (field: FieldValues) => {
let errorStr = '';
let inputName = field?.name;
if (errors && errors?.[inputName]) {
errorStr = errors?.[inputName]?.message;
}
return errorStr;
}
return (
<>
<h3>Sample React hook form</h3>
<form onSubmit={handleSubmit(onSubmit, one rror)}>
<Controller
name="user_name"
control={control}
rules={{ validate: {isRequired: ruleSet.isRequired, minLen: ruleSet.minLen, maxLen: ruleSet.maxLen } }}
render={({ field, fieldState: {error}, formState }) =>
<MyTextField placeholder="Enter user name here" error={!!error} {...field} />
}
/>
<br/>
<Controller
name="password"
control={control}
rules={{ validate: {isRequired: ruleSet.isRequired, minLen: ruleSet.minLen, maxLen: ruleSet.maxLen } }}
render={({ field, fieldState: {error}, formState }) =>
<MyTextField placeholder="Enter password here" error={!!error} {...field} />
}
/>
<br/>
<Controller
name="retype_password"
control={control}
rules={{ validate: {isRequired: ruleSet.isRequired, minMaxLen: ruleSet.minMaxLen, ruleSet.isValueEqual } }}
render={({ field, fieldState: {error}, formState }) =>
<MyTextField placeholder="Retype password here" error={!!error} {...field} />
}
/>
<br/>
<MyButton color="primary" type="submit">
Submit Form
</MyButton>
</form>
</>
);
};
Common Rules file
export const isRequired = (value: string) => {
return value ? true : 'This is a required input, can not escape';
}
export const maxLen = (value: string) => {
// console.log('Get values', getValues());
return value.length <= 15 || 'Value cannot be more than 15 chars';
}
const minLen = (value: string) => {
// console.log('Get values', getValues());
return value.length >= 7 || 'Value cannot be less than 7 chars';
}
const minMaxLen = (value: string) => { // Here i want to get dynamic parameter for min and max so that it can be used in various forms
return value.length >= <SomeMinValue> && value.length <= <SomeMaxValue> || 'Should be between ${SomeMinValue} and ${SomeMaxValue} chars';
}
const isValueEqual = (value: string) => {
const valOfFieldToBeComparedWith = getValues('password'); // Check how to pass params dynamically to validate function
console.log("retype password is", valOfFieldToBeComparedWith);
return value === valOfFieldToBeComparedWith || 'Password and retype password do not match';
}
export const ruleSet = {
isRequired,
minLen,
maxLen,
minMaxLen,
isValueEqual
}
I basically need a way to pass parameters to these functions defined in rules file so from the form component.
Any guidance will be highly appreciated. Thank you
CodePudding user response:
You can wrap the validation function so that you can set the min/max params.
const makeMinMaxLen = (min: number, max: number) => (value: string) => {
return value.length >= min && value.length <= max || 'Should be between ${min} and ${max} chars';
}
<Controller
name="retype_password"
control={control}
rules={{ validate: {isRequired: ruleSet.isRequired, minMaxLen: ruleSet.makeMinMaxLen(4, 16), ruleSet.isValueEqual } }}
render={({ field, fieldState: {error}, formState }) =>
<MyTextField placeholder="Retype password here" error={!!error} {...field} />
}
/>
Even better is to store the composed function outside the render function