Skip to content

Instantly share code, notes, and snippets.

@reksamamur
Last active September 5, 2022 02:34
Show Gist options
  • Save reksamamur/3d88fd9549fec2e35f0f5fee36cac167 to your computer and use it in GitHub Desktop.
Save reksamamur/3d88fd9549fec2e35f0f5fee36cac167 to your computer and use it in GitHub Desktop.
Multi Nested Field Array using react-hook-form
import "./styles.css";
import {
useForm,
FormProvider,
useFormContext,
useFieldArray,
UseFieldArrayReturn
} from "react-hook-form";
import { useImperativeHandle, useRef, forwardRef } from "react";
interface InputMultiProps {
depth: number;
formParentName: string;
index: number;
fieldArray: any;
}
const InputMulti = ({
depth,
formParentName,
index,
fieldArray
}: InputMultiProps) => {
const formName = `${formParentName}.${index}`;
const formNameNested = `${formName}.children`;
const { append, remove, move, fields } = fieldArray;
const { register, control } = useFormContext();
const {
fields: nestedFields,
append: nestedAppend,
remove: nestedRemove,
move: nestedMove
} = useFieldArray({
control,
name: formNameNested
});
return (
<>
<div style={{ paddingLeft: depth * 10 }}>
<input
type="text"
placeholder="name"
required
{...register(`${formName}.value` as const)}
/>
<button
type="button"
onClick={() =>
append({
value: "",
depth: depth,
children: []
})
}
>
Add
</button>
<button
type="button"
onClick={() =>
nestedAppend({
value: "",
depth: depth + 1,
children: []
})
}
>
Add Nested
</button>
<button type="button" onClick={() => remove(index)}>
Delete
</button>
{index === 0 ? (
<>
<button
type="button"
onClick={() => move(index, index - 1)}
disabled
>
Move Up
</button>
</>
) : (
<>
<button type="button" onClick={() => move(index, index - 1)}>
Move Up
</button>
</>
)}
{index === fields.length - 1 ? (
<button type="button" disabled onClick={() => move(index, index + 1)}>
Move Down
</button>
) : (
<button type="button" onClick={() => move(index, index + 1)}>
Move Down
</button>
)}
</div>
{nestedFields.map((field, index) => (
<InputMulti
key={field.id}
depth={depth + 1}
index={index}
formParentName={formNameNested}
fieldArray={{
append: nestedAppend,
remove: nestedRemove,
move: nestedMove,
fields: nestedFields
}}
/>
))}
</>
);
};
const CustomForm = () => {
const { control, handleSubmit } = useFormContext();
const fieldArrayName = "parent";
const { fields, append, remove, move } = useFieldArray({
control,
name: fieldArrayName
});
const onSubmit = (data: any) => {
console.log("data", data);
};
return (
<>
<form id="hook-form" onSubmit={handleSubmit(onSubmit)}>
{fields.length < 1 ? (
<button onClick={() => append({ value: "", depth: 0, children: [] })}>
First Field
</button>
) : (
<></>
)}
{fields.map((field, index) => (
<InputMulti
key={field.id}
depth={0}
index={index}
formParentName={`parent`}
fieldArray={{ append, remove, move, fields }}
/>
))}
<input style={{ marginTop: 20 }} type="submit" value="Submit" />
</form>
</>
);
};
export default function App() {
/**
#example of using predefined value
const defaultValues = {
parent: [
{
value: "Te st",
depth: 0,
children: []
},
{
value: " asda Sa",
depth: 0,
children: []
},
{
value: "Asda asd",
depth: 0,
children: [
{
value: "child 1",
depth: 1,
children: []
},
{
value: "child 2",
depth: 1,
children: []
}
]
}
]
};
#define defaultValues to useForm()
const methods = useForm({defaultValues});
**/
const methods = useForm();
return (
<div className="App">
<FormProvider {...methods}>
<CustomForm />
</FormProvider>
</div>
);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment