Reputation: 4192
My react application take data from user and should output them when user click on SUBMIT
button.
Now user open the application appears a number input. There he can set a number, for example 2. After that appears 2 boxes, where user can add fields
cliking on the button +
. In each field user have to add his name and last name. Now the application works, but no in the right way.
Now, if user add his user name and last name in first box and click on SUBMIT
, everithing appears in:
const onFinish = values => {
const res = {
data: [dataAll]
};
console.log("Received values of form:", res);
};
But if user add one another inputs clicking on add fields
button, the first data dissapears. The same issue is when user add data in 2 boxes, the data is saved just from the last box.
function handleInputChange(value) {
const newArray = Array.from({ length: value }, (_, index) => index + 1);
setNr(newArray);
}
const onFinish = values => {
const res = {
data: [dataAll]
};
console.log("Received values of form:", res);
};
return (
<div>
<Form name="outter" onFinish={onFinish}>
{nr.map(i => (
<div>
<p key={i}>{i}</p>
<Child setDataAll={setDataAll} nr={i} />
</div>
))}
<Form.Item
name={["user", "nr"]}
label="Nr"
rules={[{ type: "number", min: 0, max: 7 }]}
>
<InputNumber onChange={handleInputChange} />
</Form.Item>
<Form.Item>
<Button htmlType="submit" type="primary">
Submit
</Button>
</Form.Item>
</Form>
</div>
);
};
Mu expected result after clicking on submit is:
data:[
{
nr:1,
user: [
{
firstName:'John',
lastName: 'Doe'
},
{
firstName:'Bill',
lastName: 'White'
}
]
},
{
nr:2,
user: [
{
firstName:'Carl',
lastName: 'Doe'
},
{
firstName:'Mike',
lastName: 'Green'
},
{
firstName:'Sarah',
lastName: 'Doe'
}
]
},
]
....
// object depend by how many fields user added in each nr
Question: How to achieve the above result?
demo: https://codesandbox.io/s/wandering-wind-3xgm7?file=/src/Main.js:288-1158
Upvotes: 0
Views: 235
Reputation: 11283
Here's an example how you could do it.
As you can see Child
became Presentational Component and only shows data.
Rest of logic went to the Parent component.
const { useState, useEffect, Fragment } = React;
const Child = ({nr, user, onAddField, onChange}) => {
return <div>
<div>{nr}</div>
{user.map(({firstName, lastName}, index) => <div key={index}>
<input onChange={({target: {name, value}}) => onChange(nr, index, name, value)} value={firstName} name="firstName" type="text"/>
<input onChange={({target: {name, value}}) => onChange(nr, index, name, value)} value={lastName} name="lastName" type="text"/>
</div>)}
<button onClick={() => onAddField(nr)}>Add Field</button>
</div>
}
const App = () => {
const [items, setItems] = useState([
{
nr: 1,
user: []
},
{
nr: 2,
user: [
{firstName: 'test1', lastName: 'test1'},
{firstName: 'test2', lastName: 'test2'}
]
}
]);
const onCountChange = ({target: {value}}) => {
setItems(items => {
const computedList = Array(Number(value)).fill(0).map((pr, index) => ({
nr: index + 1,
user: []
}))
const merged = computedList.reduce((acc, value) => {
const item = items.find(pr => pr.nr === value.nr) || value;
acc = [...acc, item];
return acc;
}, [])
return merged;
})
}
const onChildChange = (nr, index, name, value) => {
setItems(items => {
const newItems = [...items];
const item = newItems.find(pr => pr.nr === nr);
const field = item.user.find((pr, ind) => index === ind)
field[name] = value;
return newItems;
});
}
const onAddField = (nr) => {
setItems(items => {
const newItems = [...items];
const item = newItems.find(pr => pr.nr === nr);
item.user = [...item.user, {
firstName: '',
lastName: ''
}];
return newItems;
})
}
const onClick = () => {
console.log({data: items});
}
return <div>
{items.map((pr, index) => <Child {...pr} onAddField={onAddField} onChange={onChildChange} key={index} />)}
<input onChange={onCountChange} value={items.length} type="number"/>
<button onClick={onClick}>Submit</button>
</div>
}
ReactDOM.render(
<App />,
document.getElementById('root')
);
<script src="https://unpkg.com/react/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
<div id="root"></div>
Upvotes: 1