I have a input form that can dynamically add new inputs like this:
const [inputVariationFields, setInputVariationFields] = useState<AddProductVariationForm[]>([])
const addVariationFields = () => {
let newfield = AddProductVariationInitialValue
setInputVariationFields([...inputVariationFields, newfield])
}
let removeVariationFields = (i: number) => {
let newFormValues = [...inputVariationFields];
newFormValues.splice(i, 1);
setInputVariationFields(newFormValues)
}
{
inputVariationFields.map((element, index) => (
<div className="my-3 p-3 border border-gray-lighter rounded" key={index}>
<div className='w-full'>
<label htmlFor={'name_1_' index.toString} className='font'>
Variation Name 1
<BaseInput
key={'name_1_' index.toString}
id={index.toString()}
name={'name_1_' index.toString}
type='text'
value={element.name_1 || ''}
onChange={(e) => {
let newFormValues = [...inputVariationFields];
console.log(newFormValues)
newFormValues[index].name_1 = e.target.value;
setInputVariationFields(newFormValues);
}}
value={element.name_1 || ''}
placeholder='Product variation name 1'
/>
</label>
</div>
...
{
index ?
<div className='mt-5 mb-2'>
<OutlinedButton key={index} onClick={() => removeVariationFields(index)}>
Remove
</OutlinedButton>
</div>
: null
}
</div>
))
}
<div className="my-3">
<PrimaryButton
type='button'
onClick={() => addVariationFields()}
>
Add variation
</PrimaryButton>
</div>
But when I add the new variation field, and insert the value of name_1, it change the value of the new variation name_1 field as well. How to insert name_1 with different value of each variation?
Note: I'm using typescript and the InputVariationField is an array of object that have keys like name_1 and more.
CodePudding user response:
I mean, the init value of inputVariationFields
like:
const [inputVariationFields, setInputVariationFields] = useState([{ name_1: "" }]);
In addVariationFields
function, you must init a object with name_1
is empty, like:
const addVariationFields = () => {
const newfield = { name_1: "" };
setInputVariationFields([...inputVariationFields, newfield]);
};
Error in your onChange
handle and value
of input
. I make a new function to handle onChange
of input
.
const onChangeInput = (e, index) => {
e.preventDefault();
const newArray = inputVariationFields.map((ele, i) => {
if (index === i) {
ele.name_1 = e.target.value;
}
return ele;
});
setInputVariationFields(newArray);
}
{
inputVariationFields.map((element, index) => (
<div className="my-3 p-3 border border-gray-lighter rounded" key={index}>
<div className='w-full'>
<label htmlFor={'name_1_' index.toString} className='font'>
Variation Name {index 1}
<BaseInput
key={'name_1_' index.toString}
id={index.toString()}
name={'name_1_' index.toString}
type='text'
onChange={(e) => onChangeInput(e, index)}
value={element.name_1 || ""}
placeholder={`Product variation name ` (index 1)}
/>
</label>
</div>
{
index ?
<div className='mt-5 mb-2'>
<OutlinedButton key={index} onClick={() => removeVariationFields(index)}>
Remove
</OutlinedButton>
</div>
: null
}
</div>
))
}
Check out:
https://codesandbox.io/s/friendly-forest-38esp3?file=/src/Test.js
Hope that it helps
CodePudding user response:
You are spreading the same object ("newField") into inputVariationFields
every time you call addVariationFields
. This causes every element in the array to be a pointer to the same object. So everytime you change a property of one element it changes the same property of every other element in the array.
To solve this mistake add a new object when calling addVariationFields
instead of the same each time.
You can do this by creating a new object with {...AddProductVariationInitialValue}
This new object will have the same properties as .AddProductVariationInitialValue
.
const addVariationFields = () => {
let newfield = {...AddProductVariationInitialValue}
setInputVariationFields([...inputVariationFields, newfield])
}
I hope this solves your problem