usefieldarray example for dynamic input field with react and yup validation #11982
Unanswered
aravind-satyan
asked this question in
General
Replies: 1 comment
|
You are very close. The main thing to fix is the Because your field array is named features.${index}.featureEn
features.${index}.featureArNot: featureEn${index}
featureAr${index}Example child component: const FeaturesDetails = ({ control, errors, fields, append, remove }) => (
<>
{fields.map((item, index) => (
<React.Fragment key={item.id}>
<Controller
control={control}
name={`features.${index}.featureEn`}
render={({ field }) => (
<TextField
{...field}
label="Feature En"
error={!!errors.features?.[index]?.featureEn}
helperText={errors.features?.[index]?.featureEn?.message}
/>
)}
/>
<Controller
control={control}
name={`features.${index}.featureAr`}
render={({ field }) => (
<TextField
{...field}
label="Feature Ar"
error={!!errors.features?.[index]?.featureAr}
helperText={errors.features?.[index]?.featureAr?.message}
/>
)}
/>
<IconButton disabled={fields.length === 1} onClick={() => remove(index)}>
<Remove />
</IconButton>
</React.Fragment>
))}
<Button onClick={() => append({ featureEn: "", featureAr: "" })}>
Add Feature
</Button>
</>
);Your Yup schema should match that same shape: const schema = Yup.object({
features: Yup.array().of(
Yup.object({
featureEn: Yup.string().required("Feature En is required"),
featureAr: Yup.string().required("Feature Ar is required"),
})
),
});Then {
features: [
{ featureEn: "...", featureAr: "..." }
]
}The important parts are: use Hope this helps — if you share a minimal reproduction, I can adjust the code to your exact setup. |
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Hello everyone,
am trying to implement a dynamic form with 2 input fields using the useFiledArray hook. as a beginner, am facing some issues about getting the values properly for you validation. below is my parent component and child component used. can somebody help me on this?
Parent component
import React, { useEffect, useState } from "react";
import {
Button,
Card,
CardContent,
CardHeader,
Divider,
Grid,
Step,
StepContent,
StepLabel,
Stepper,
ThemeProvider,
Typography,
createTheme,
} from "@mui/material";
import { useForm, useFieldArray } from "react-hook-form";
import { yupResolver } from "@hookform/resolvers/yup";
import * as Yup from "yup";
import BasicDetails from "./Forms/BasicDetails";
import ServiceDetails from "./Forms/ServiceDetails";
import WarrantyDetails from "./Forms/WarrantyDetails";
import ContactDetails from "./Forms/ContactDetails";
import FeaturesDetails from "./Forms/FeaturesDetails";
const AddCar = () => {
const steps = [
{
label: "Basic Details",
description: "",
},
];
const schema = [
Yup.object().shape({
}),
];
const [activeStep, setActiveStep] = useState(0);
const currentValidationSchema = schema[activeStep];
const isLastStep = activeStep === steps.length - 1;
const {
control,
ref,
handleSubmit,
formState: { errors },
} = useForm({
defaultValues: {
features: [{ featureEn: "", featureAr: "" }],
},
mode: "onBlur",
resolver: yupResolver(currentValidationSchema),
});
const { fields, append, remove } = useFieldArray({
control,
name: "features",
});
const handleNext = () => {
setActiveStep((prevActiveStep) =>
prevActiveStep === steps.length ? prevActiveStep : prevActiveStep + 1
);
};
const renderStepContent = (step) => {
switch (step) {
case 0:
return ;
case 1:
return (
);
case 2:
return ;
case 3:
return ;
case 4:
return ;
default:
return null;
}
};
const submitForm = (values) => {
console.log(values);
if (values?.serviceTillDate !== "") {
const date = new Date(values?.serviceTillDate);
const formattedDate = date.toLocaleDateString("en-GB");
const serviceTill = formattedDate.replace(///g, "-");
console.log(serviceTill);
}
if (values?.warrentyTillDate !== "") {
const date = new Date(values?.warrentyTillDate);
const formattedDate = date.toLocaleDateString("en-GB");
const warrantyTill = formattedDate.replace(///g, "-");
console.log(warrantyTill);
}
};
const onSubmit = async (values) => {
console.log(values);
if (isLastStep) {
submitForm(values);
} else {
handleNext();
console.log(activeStep);
}
};
return (
<Grid container sx={{ display: "flex", justifyContent: "center" }}>
{steps.map((step, index) => (
<StepLabel
sx={{
alignItems: "baseline",
}}
>
{step.label}
{step.description}
{renderStepContent(activeStep)}
))}
<Grid
container
spacing={2}
sx={{ mt: 2, justifyContent: "flex-end" }}
>
<Grid
item
xs={12}
md={6}
sx={{
display: "flex",
justifyContent: "flex-end",
padding: "1rem 5rem",
}}
>
{activeStep === steps.length - 1 ? "Submit" : "Next"}
);
};
export default AddCar;
child component
import React from "react";
import { Controller } from "react-hook-form";
import {
TextField,
Button,
Grid,
FormControl,
IconButton,
} from "@mui/material";
import { Add, Remove } from "@mui/icons-material";
const FeaturesDetails = ({ control, errors, fields, append, remove }) => {
const addFeature = () => {
append({ featureEn: "", featureAr: "" });
};
const removeFeature = (index) => {
remove(index);
};
return (
<>
{fields.map((field, index) => (
<>
<Controller
control={control}
name={
featureEn${index}}defaultValue=""
render={({ field, fieldState }) => (
<TextField
{...field}
label="Feature En"
variant="outlined"
size="small"
type="text"
multiline
error={!!errors.features?.[index]?.featureEn}
helperText={errors.features?.[index]?.featureEn?.message}
/>
)}
/>
<Controller
control={control}
name={
featureAr${index}}defaultValue=""
render={({ field, fieldState }) => (
<TextField
{...field}
label="Feature Ar"
variant="outlined"
size="small"
type="text"
multiline
error={!!errors.features?.[index]?.featureAr}
helperText={errors.features?.[index]?.featureAr?.message}
/>
)}
/>
);
};
export default FeaturesDetails;
All reactions