Replies: 2 comments 1 reply
-
Can you share an example URL or image of what you're trying to achieve? |
Beta Was this translation helpful? Give feedback.
1 reply
-
Here is mine // 1. A COMPONENT
import React, { useState } from "react";
interface FormRepeaterProps<T> {
initialValues: T;
renderFields: (item: T, index: number, handleChange: (index: number, name: keyof T, value: any) => void) => React.ReactNode;
onAdd?: () => void;
onRemove?: (index: number) => void;
}
export default function FormRepeater<T>({
initialValues,
renderFields,
onAdd,
onRemove,
}: FormRepeaterProps<T>) {
const [items, setItems] = useState<T[]>([initialValues]);
const handleAdd = () => {
setItems((prev) => [...prev, initialValues]);
onAdd?.();
};
const handleRemove = (index: number) => {
setItems((prev) => prev.filter((_, i) => i !== index));
onRemove?.(index);
};
const handleChange = (index: number, name: keyof T, value: any) => {
const updatedItems = [...items];
updatedItems[index] = { ...updatedItems[index], [name]: value };
setItems(updatedItems);
};
return (
<div>
{items.map((item, index) => (
<div key={index} className="mb-4 p-4 border rounded-lg shadow-sm">
<div>{renderFields(item, index, (i, name, value) => handleChange(i, name, value))}</div>
{items.length > 1 && (
<button
type="button"
onClick={() => handleRemove(index)}
className="text-red-600 text-sm mt-2"
>
Remove
</button>
)}
</div>
))}
<button
type="button"
onClick={handleAdd}
className="px-4 py-2 mt-2 text-white bg-indigo-500 rounded-md hover:bg-indigo-600"
>
Add More
</button>
</div>
);
} You can use it anywhere like this import React from "react";
import FormRepeater from "./form-repeater";
import { Input } from "./ui/input";
interface Product {
name: string;
quantity: number;
price: number;
}
export default function AddProductsForm() {
const initialProduct: Product = { name: "", quantity: 0, price: 0 };
const handleSubmit = (data: Product[]) => {
console.log("Submitted Products:", data);
};
return (
<form
onSubmit={(e) => {
e.preventDefault();
// Collect form data and handle submission
}}
>
<h1 className="text-xl font-semibold mb-4">Add Products</h1>
<FormRepeater<Product>
initialValues={initialProduct}
renderFields={(item, index, handleChange) => (
<div className="grid grid-cols-3 gap-4">
<div>
<label className="block text-sm font-medium">Product Name</label>
<Input
type="text"
value={item.name}
onChange={(e) => handleChange(index, "name", e.target.value)}
className="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
/>
</div>
<div>
<label className="block text-sm font-medium">Quantity</label>
<Input
type="number"
value={item.quantity}
onChange={(e) => handleChange(index, "quantity", parseInt(e.target.value) || 0)}
className="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
/>
</div>
<div>
<label className="block text-sm font-medium">Price</label>
<Input
type="number"
value={item.price}
onChange={(e) => handleChange(index, "price", parseFloat(e.target.value) || 0)}
className="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
/>
</div>
</div>
)}
/>
<button
type="submit"
className="mt-4 px-6 py-2 bg-green-500 text-white rounded-md hover:bg-green-600"
>
Submit
</button>
</form>
);
} |
Beta Was this translation helpful? Give feedback.
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.
-
Hi!
Anybody made a form with repeater select field? Any idea how to start with it?
Many Thanx!
Beta Was this translation helpful? Give feedback.
All reactions