I created a model for a form which maps throught it to create form using react-hook-form
when i submit form for the first time, everything is Okay. but for the other times, when i paste a value into inputs, validation not work correctly(it shows required error but the input is not empty)
this is model:
export const formData = [
{
id: 1,
type: "text",
labelRequired: true,
label: "name",
shape: "inline",
placeholder: "name",
name: "nameOne",
validation: {
required: true,
minLength: 8,
},
size: 6,
},
{
id: 2,
type: "text",
labelRequired: true,
label: "family",
shape: "inline",
placeholder: "family",
name: "nameTwo",
validation: {
required: true,
minLength: 8,
},
size: 6,
},
{
id: 7,
type: "checkbox",
label: "Sample",
shape: "checkbox",
placeholder: "placeholder",
name: "checkbox_btn",
data: [
{
id: 41,
inputId: "inline-form-1",
label: "1",
},
],
size: 12,
},
];
the map method to create form based on model:
const Sample = () => {
const {
register,
handleSubmit,
formState: { errors },
reset,
} = useForm({
mode: "onBlur",
});
const submitHandler = (data, e) => {
e.target.reset();
console.log(data);
reset();
};
const mapForm = formData.map((item) => {
if (item.shape === "inline") {
return (
<InputContainer
key={item.id}
register={{
...register(item.name, {
required: item.validation.required,
minLength: item.validation.minLength,
}),
}}
validation={item.validation}
placeholder={item.placeholder}
label={item.label}
size={item.size}
error={errors[item.name]}
/>
);
}
if (item.shape === "checkbox") {
return (
<CheckBoxContainer
key={item.id}
label={item.label}
data={item.data}
register={{ ...register("medium", { required: true }) }}
error={errors.medium}
/>
);
}
});
return (
<Fragment>
<Breadcrumb parent="Dashboard" title="Default" />
<Container fluid={true}>
<Row>
<Col sm="12">
<Card>
<CardHeader>
<h5>Sample Card</h5>
</CardHeader>
<CardBody>
<Form onSubmit={handleSubmit(submitHandler)}>
<Row>{mapForm}</Row>
<Button type="submit" className="m-t-40">
Submit
</Button>
</Form>
</CardBody>
</Card>
</Col>
</Row>
</Container>
</Fragment>
);
};
export default Sample;
Also there are some container components for wrapping inputs like:
const InputContainer = ({
id,
register,
error,
label,
labelRequired,
size,
type,
placeholder,
validation,
}) => {
return (
<Col lg={size} style={{ marginTop: "-10px" }}>
<FormGroup>
<Label className={`col-form-label`}>
{label} {labelRequired && <span></span>}
</Label>
<Input
className="form-control"
type={type}
placeholder={placeholder}
{...register}
/>
{error && error.type === "required" && (
<p className="p-16 text-danger">this filed is required</p>
)}
</FormGroup>
</Col>
);
};
export default InputContainer;
I have not looked that deep into it to find out if this happens from a simple misuse of the useForm() hook, but here's what I've figured out.
According to the source code, register() returns the following interface (unrelated stuff omitted):
type UseFormRegisterReturn<...> = {
onChange: ChangeHandler;
onBlur: ChangeHandler;
ref: RefCallBack;
...
}
As you can see, this means only the onChange() and onBlur() events are being registered. onChange() is the one we're interested in.
After some quick testing, I've realized that for some unknown reason (maybe a browser bug? no idea), in certain conditions onChange() doesn't trigger when pasting text with CTRL+V.
Luckily, the regular onInput() event still triggers, so we can simply define this event using the register.onChange() handler:
<Input
className="form-control"
type={type}
placeholder={placeholder}
{...register}
onInput={register && register.onChange}
// TypeScript
// onInput={register?.onChange}
/>
If onInput() is already being used:
<Input
className="form-control"
type={type}
placeholder={placeholder}
{...register}
onInput={e => {
doOtherStuff(e);
if (register && register.onChange) {
register.onChange(e);
}
// TypeScript
// register?.onChange(e);
}
/>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With