Hi I use a search box made using React and Material UI/MUI that references a json file which has the tags id, firstname, lastname, address, city, zip. The search box searches the emails for matching the input characters. The matched values are rendered as a dynamic table that changes as more and more characters are typed. I have made edit buttons for each table row that loads but I am not able to successfully edit any entry. Upon using the console in Dev Tools in Chrome, I found a warning for each child to have a key in List.js but I tried using {key=item.id} in several locations like the Fragment tag and the EditableRow tag. Can I please get some ideas on this? Thanks in advance !!!
Here is my code
import TextField from "@mui/material/TextField";
import List from "./Components/List";
import "./App.css";
function App() {
const [inputText, setInputText] = useState("");
let inputHandler = (e) => {
//convert input text to lower case
var lowerCase = e.target.value.toLowerCase();
setInputText(lowerCase);
};
return (
<div className="main">
<h1>Search</h1>
<div className="search">
<TextField
id="outlined-basic"
onChange={inputHandler}
variant="outlined"
fullWidth
label="Search"
/>
</div>
<List input={inputText} />
</div>
);
}
export default App;
The App.js is the main wrapper for the search box, all the search logic and table rendering logic is found in List.js below (to be place in a Components folder in the same dir as the App.js file)
import data from "./ListData.json"
import ReadOnlyRow from "./ReadOnlyRow.js"
import EditableRow from "./EditableRow.js"
function List(props) {
const [contacts, setContacts]=useState(data);
const [editContactId, setEditContactId] = useState(null);
const [editFormData, setEditFormData] = useState({
CustomerLogonId: "",
FirstName: "",
LastName: "",
Address: "",
City: "",
Zip: "",
});
const handleFormChange = (event) => {
event.preventDefault();
const fieldName = event.target.getAttribute("name");
const fieldValue = event.target.value;
const newFormData = {...editFormData};
newFormData[fieldName] = fieldValue;
setEditFormData(newFormData);
};
const handleFormSubmit = (event) => {
event.preventDefault();
const editedContact = {
id : editContactId,
CustomerLogonId: editFormData.CustomerLogonId,
FirstName: editFormData.FirstName,
LastName: editFormData.LastName,
Address: editFormData.Address,
City: editFormData.City,
Zip: editFormData.Zip
}
const newContacts = [...contacts];
const index = contacts.findIndex((item) => item.id === editContactId)
newContacts[index] = editedContact;
setContacts(newContacts);
setEditContactId(null);
}
const handleEditClick = (event, item) => {
event.preventDefault();
setEditContactId(item.id);
const formValues = {
CustomerLogonId: item.CustomerLogonId,
FirstName: item.FirstName,
LastName: item.LastName,
Address: item.Address,
City: item.City,
Zip: item.Zip
}
setEditFormData(formValues);
}
const handleCancelClick = () => {
setEditContactId(null);
};
//create a new array by filtering the original array
const filteredData = data.filter((el) => {
//if no input then return a empty string
if (props.input === '') {
return '';
}
//return the customer which contains the user input email id
else {
return el.CustomerLogonId.toLowerCase().includes(props.input)
}
})
return (
<div className='app-container'>
<form onSubmit={handleFormSubmit}>
<table>
<thead>
<tr>
<th>CustomerLogonId</th>
<th>FirstName</th>
<th>LastName</th>
<th>Address</th>
<th>City</th>
<th>Zip</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{filteredData.map((item) => (
<Fragment>
{editContactId === item.id ? (<EditableRow key={item.id} editFormData={editFormData} handleFormChange={handleFormChange} handleCancelClick={handleCancelClick} />) : (<ReadOnlyRow key={item.id} item = {item} handleEditClick = {handleEditClick} />) }
</Fragment>
))}
</tbody>
</table>
</form>
</div>
)
}
export default List
Here are the ReadableRow and EditableRow files (which should be placed in the Components folder as well)
import React from "react";
const ReadOnlyRow = ({ item, handleEditClick }) => {
return (
<tr>
<td>{item.CustomerLogonId}</td>
<td>{item.FirstName}</td>
<td>{item.LastName}</td>
<td>{item.Address}</td>
<td>{item.City}</td>
<td>{item.Zip}</td>
<td><button type="button" onClick={(event)=> handleEditClick(event,item)}>Edit</button></td>
</tr>);
};
export default ReadOnlyRow;
import React from "react";
const EditableRow = ({ editFormData, handleFormChange, handleCancelClick }) => {
return (
<tr>
<td><input type="text" required="required" placeholder="Enter the email.." name="CustomerLogonId" value={editFormData.CustomerLogonId} onChange={handleFormChange}></input></td>
<td><input type="text" required="required" placeholder="Enter the firstname.." name="FirstName" value={editFormData.FirstName} onChange={handleFormChange}></input></td>
<td><input type="text" required="required" placeholder="Enter the lastname.." name="LastName" value={editFormData.LastName} onChange={handleFormChange}></input></td>
<td><input type="text" required="required" placeholder="Enter the address.." name="Address" value={editFormData.Address} onChange={handleFormChange}></input></td>
<td><input type="text" required="required" placeholder="Enter the city.." name="City" value={editFormData.City} onChange={handleFormChange}></input></td>
<td><input type="text" required="required" placeholder="Enter the zip.." name="Zip" value={editFormData.Zip } onChange={handleFormChange}></input></td>
<td><button type="submit">Save</button><button type = "button" onClick={handleCancelClick}>Cancel</button></td>
</tr>);
};
export default EditableRow;
Here's also the JSON file if you want to take a crack at this
[{
"id": 1,
"CustomerLogonId": "albertlee@email.com",
"FirstName": "Albert",
"LastName" : "Lee",
"Address" : "Street 1",
"City" : "A",
"Zip" : "000001"
}, {
"id": 2,
"CustomerLogonId": "berthasummers@email.com",
"FirstName": "Bertha",
"LastName" : "Summers",
"Address" : "Lane 2",
"City" : "A",
"Zip" : "000001"
}, {
"id": 3,
"CustomerLogonId": "carljohnson@email.com",
"FirstName": "Carl",
"LastName" : "Johnson",
"Address" : "Street 3",
"City" : "B",
"Zip" : "000001"
}, {
"id": 4,
"CustomerLogonId": "dusterjones@email.com",
"FirstName": "Duster",
"LastName" : "Jones",
"Address" : "Lane 4",
"City" : "B",
"Zip" : "000002"
}, {
"id": 5,
"CustomerLogonId": "earljonessmith@email.com",
"FirstName": "Earl Jones",
"LastName" : "Smith",
"Address" : "Street 4",
"City" : "B",
"Zip" : "000003"
}, {
"id": 6,
"CustomerLogonId": "feliciahardy@email.com",
"FirstName": "Felicia",
"LastName" : "Hardy",
"Address" : "Lane 5",
"City" : "B",
"Zip" : "000003"
}, {
"id": 7,
"CustomerLogonId": "georgeharrison@email.com",
"FirstName": "George",
"LastName" : "Harrison",
"Address" : "Street 6",
"City" : "C",
"Zip" : "000004"
}, {
"id": 8,
"CustomerLogonId": "harrypotter@email.com",
"FirstName": "Harry",
"LastName" : "Potter",
"Address" : "Gryffindor House",
"City" : "Hogwarts",
"Zip" : "000934"
}, {
"id": 9,
"CustomerLogonId": "indiasummers@email.com",
"FirstName": "India",
"LastName" : "Summers",
"Address" : "Land 9",
"City" : "A",
"Zip" : "000005"
}, {
"id": 10,
"CustomerLogonId": "jamesbond@email.com",
"FirstName": "James",
"LastName" : "Bond",
"Address" : "Mi6",
"City" : "B",
"Zip" : "000005"
},
{
"id": 11,
"CustomerLogonId": "georgeforeman@email.com",
"FirstName": "George",
"LastName" : "Foreman",
"Address" : "Street 6",
"City" : "C",
"Zip" : "000004"
}]