Reputation: 655
I have form where user can add as much as he wants documents. Each document have several inputs. And I'm trying to get each document inputs values and put it to state as array of objects. State should look like:
[
{
id: 'UGN2WP68P1',
name: 'passport',
placeIssue: 'paris'
},
{
id: 'TD0KUWWIM6',
name: 'shengen visa',
placeIssue: 'paris'
}
...
]
So I write a function which is called on inputs change. He check are there object with same id, if there is no object with same id he creates new and add to array, if object exist with same id then he update object:
const addNewDocumentObj = (id, type, val) => {
// Get object with same id
let docObj = addedDocsArr.filter( el => el.id === id)
// If there is no object with same id, creates new one
if (docObj.length === 0) {
if (type === 'name'){
let obj = {
id: id,
docId: val.id
}
setAddedDocsArr(addedDocsArr.concat(obj))
} else if (type === 'placeIssue') {
let obj = {
id: id,
placeIssue: val
}
setAddedDocsArr(addedDocsArr.concat(obj))
}
// If object exist with same id then updates with new value and adds to array
} else {
if (type === 'name'){
let newObject = Object.assign(docObj, {name: val.id})
let newArray = addedDocsArr.filter(el => el.id !== id)
setAddedDocsArr(newArray.concat(newObject))
} else if (type === 'placeIssue') {
let newObject = Object.assign(docObj, {placeIssue: val})
let newArray = addedDocsArr.filter(el => el.id !== id)
setAddedDocsArr(newArray.concat(newObject))
}
}
}
But it doesn't work, and I can't understand why, maybe my logic is bad and there is better practise?
UPDATE: In React debugger I noticed how state changes. If I add select document name, in state object looks like that:
{name: 'passport', id: 'UGN2WP68P1'}
If I enter document place of issue value. Then object changes and show data like that:
{placeIssue: 'paris', id: 'UGN2WP68P1'}
But result should be:
{name: 'passport', placeIssue: 'paris', id: 'UGN2WP68P1'}
So it looks like that object not updated but created new one
Upvotes: 0
Views: 100
Reputation: 655
I find a pretty easy way how to solve this problem. I read documentations of react forms and find multiple inputs idea React Forms So I changed my code to:
// Update or add information of added documents inputs
const addNewDocumentObj = (id, e, name) => {
const newInput = addedDocsArr.map(el => {
if(id === el.id) {
if(name === 'name'){
el[name] = e.target.value
} else if (name === 'placeIssue'){
el[name] = e.target.value
}
}
return el
})
setAddedDocsArr(newInput);
}
// Add new document inputs
const addNewDocument = () => {
let blockId = randomNumber(10, true, false)
setAddedDocsArr([...addedDocsArr, {id: blockId, name: '', placeIssue: ''}])
}
And it works perfectly!
Upvotes: 0
Reputation: 10675
Finished App:
Implementation of Handle submit:
const handleSubmit = (event) => {
event.preventDefault();
if (!uid) {
alert("Please enter the ID");
return;
}
let existingRecords = docs.filter((doc) => doc.id === uid);
if (!existingRecords.length) {
let newRecord = {
id: uid,
name: name,
issuePlace: place
};
setDocs([...docs, newRecord]);
setId("");
setName("");
setPlace("");
} else {
let unmodifiedRecords = docs.filter((doc) => doc.id !== uid);
if (name) {
existingRecords[0].name = name;
}
if (place) {
existingRecords[0].issuePlace = place;
}
unmodifiedRecords.push(existingRecords[0]);
setDocs(unmodifiedRecords);
setId("");
setName("");
setPlace("");
}
};
And Here is the full finished example:
import React, { useState } from "react";
import "./styles.css";
export default function App() {
const [docs, setDocs] = useState([
{ id: "1", name: "passport", issuePlace: "delhi" }
]);
const [uid, setId] = useState("");
const [name, setName] = useState("");
const [place, setPlace] = useState("");
const handleSubmit = (event) => {
event.preventDefault();
if (!uid) {
alert("Please enter the ID");
return;
}
let existingRecords = docs.filter((doc) => doc.id === uid);
if (!existingRecords.length) {
let newRecord = {
id: uid,
name: name,
issuePlace: place
};
setDocs([...docs, newRecord]);
setId("");
setName("");
setPlace("");
} else {
let unmodifiedRecords = docs.filter((doc) => doc.id !== uid);
if (name) {
existingRecords[0].name = name;
}
if (place) {
existingRecords[0].issuePlace = place;
}
unmodifiedRecords.push(existingRecords[0]);
setDocs(unmodifiedRecords);
setId("");
setName("");
setPlace("");
}
};
return (
<div className="App">
<form onSubmit={handleSubmit}>
<table>
<tr>
<td>
<label>ID: </label>
</td>
<td>
<input
value={uid}
onChange={(e) => {
setId(e.target.value);
}}
/>
</td>
</tr>
<tr>
<td>
<label>Name: </label>
</td>
<td>
<input
value={name}
onChange={(e) => {
setName(e.target.value);
}}
/>
</td>
</tr>
<tr>
<td>
<label>Isuue Place: </label>
</td>
<td>
<input
value={place}
onChange={(e) => {
setPlace(e.target.value);
}}
/>
</td>
</tr>
<tr>
<td>
<button type="submit">Submit</button>
</td>
</tr>
</table>
</form>
{docs.map((doc) => (
<div className="records">
<span>{"ID:" + doc.id + " "}</span>
<span>{"Name:" + doc.name + " "}</span>
<span>{"Issue Place:" + doc.issuePlace + " "}</span>
</div>
))}
</div>
);
}
Check out finished example with source code at: Codesandbox Link
Upvotes: 0
Reputation: 101
Maybe you need something like:
const addNewDocumentObj = (id, type, val) => {
// Get object with same id
let docObj = addedDocsArr.find(el => el.id === id)
// If there is no object with same id, creates new one
if (!docObj) {
docObj = { id, placeIssue: val }
// and pushes it to addedDocsArray
addedDocsArr.push(docObj)
}
if (type === 'name') {
docObj.name = val.id
} else if (type === 'placeIssue') {
docObj.placeIssue = val
}
setAddedDocsArr(addedDocsArr)
}
First of all, why are you using filter
if you are actually try to find
something in array? Just use find
.
Second, if object with given id
is already exists, there is no need to filter your array and then put that object back... Just find that object in array and update it! It is already in your array! Remember that Array
contains references to your objects, so when you grab your object from the Array
and edit it, your edit the same object that Array
have.
Last one, Idk what logic your setAddedDocsArr
function have. In my example I assume that the only thing it does is set its argument (newArray) to the variable named addedDocsArr
. So instead of that, in situation where object with given id is not present, I just push
it in old array.
Upvotes: 1