I have a multi-step form, which I am making using react, to work on validation I am using react-hook-form
.
I have already achieved 90% of things just one thing I am facing the issue is getting the second form data which is dynamic.
What I am doing is
issue
What I have done
In my main component, I am doing this for validation
const forms = [
{
fields: ['desig', 'dept'],
component: () => (
<Pro register={register} errors={errors} defaultValues={defaultValues} />
),
},
{
fields: [
`userInfo[0].fname`, // here I am facing issue if I am statically putting 0,1 then it is validating that perticular form
`userInfo[0].sirname`,
],
component: () => (
<Basic
register={register}
errors={errors}
defaultValues={defaultValues}
inputHolder={inputHolder}
deleteRow={deleteRow}
addRow={addRow}
/>
),
},
];
On click of submitting, I am doing this
const handleSubmit = (e) => {
triggerValidation(forms[currentForm].fields).then((valid) => {
if (valid) {
console.log('whole form data - ', JSON.stringify(defaultValues));
}
});
};
and here i want data as like below if two data is added in form2
{
"fname": "dsteve",
"sname": "smith",
"userInfo": [
{
"desig": "ddd",
"dept": "deptee"
},
{
"desig": "ddd",
"dept": "deptee"
}
]
}
I have done everything but here only I have been stuck, I know where the issue is
Instead of this
fields: ["fname", "sname"],
I have to do like this
fields:[`userInfo[0].name, `userInfo[0].sname],
This 0-1 I have to make dynamic as per indexes, I don't know what I am missing
I tried mapping the fields with index through inputHolder
but it did not work
Edit / Update
If I am doing like this
fields:[`userInfo[0].name`,`userInfo[1].name`, `userInfo[0].sname`,`userInfo[1].sname],
So it is taking validation for two fields, but that is manually I am doming, if user creates more fields then that should take these fields dynamically.
Here is my code sandbox, which contains the full code
Here is my code sandbox
I am open to use any new approach but that should use react-hook-form
and full fill what I am trying to do
I don't know how to progrees with my approach now
Form validation in React allows an error message to be displayed if the user has not correctly filled out the form with the expected type of input. There are several ways to validate forms in React; however, this shot will focus on creating a validator function with validation rules.
A schema is a set of rules that define how a data set should be structured. Using a tool like Zod you can define a schema, and then validate if a data set adheres to the schema's rules.
Build a Multi-Step Form in 3 Easy StepsCreate the Layout of the Form and Step Elements Using HTML. Make the Multistep Form Functional Using JavaScript. Design the Form and the Step Elements Using CSS.
You can create an array of 2 empty strings where first one represents first row F name,and second one represents first row S Name under yours inputHolder in the MainComponent:
const [inputHolder, setinputHolder] = useState([
{
id: 1,
fname: "",
sname: ""
}
]);
const [names, setNames] = useState(["", ""]);
Next,every time the user ads a new row you add to empty strings in names array.
const addRow = () => {
console.log(inputHolder.length);
let item = {
id: inputHolder.length + 1,
fname: "",
sname: ""
};
setinputHolder([...inputHolder, item]);
setNames([...names, "", ""]);
};
Where each empty string represents F name and S name. Finally,fields is set to names in second form:
fields: names,
component: (register, errors, defaultValues) => (
<Form2
register={register}
errors={errors}
defaultValues={defaultValues}
inputHolder={inputHolder}
addRow={addRow}
/>
I recommend you to use yup as a validation utils. It is a powerful tool.
import * as yup rom 'yup';
const schema = yup.object().shape({
field1: yup.string().required() // number, array - whatever,
field2: yup.string().required(),
})
Similar schema should be created for second form as well
import { yupResolver } from '@hookform/resolvers/yup';
const { register, handleSubmit } = useForm({
resolver: yupResolver(schema),
});
Do the same for your second form - useForm + validation resolver.
next part is to make your second form being dynamic, so do use hook useFieldArray
const { fields, append, remove } = useFieldArray({
name: 'userInfo', *// key, a part of path to access your fields - userInfo[n].fname*
control: form.control, *// to connect you fields to basic form*
});
Now you can create actions*(buttons/links)* and pass them {append, remove} actions.
{fields} should be rendered by .map as default. once you will try to validate your second form with (n) count off section - your schema would be applied to each of sections.
there is another solution, you can skip part with second form(I would prefer this way if your second schema could be massive).
you can connect your useFieldArray fields to first form, and your single validation schema looks like:
import * as yup rom 'yup';
const infoSchema = yup.object().schema({
firstName: yup.string(),
lastName: yup.string(),
})
*// enhance infoSchema to your expected logic.*
const schema = yup.object().shape({
field1: yup.string().required() // number, array - whatever,
field2: yup.string().required(),
userInfo: yup.array().of(infoSchema),
})
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