CRUD operation on dynamic form reactjs? - reactjs

AS a Learner in ReactJS ,I have tried to perform Crud operation on the dynamic form But failed to perform a Update operation i.e edit button .i want to pass specific row data to the ADDform component from the Appcomponent Table and edit the data in addForm Component and save the data.I am unable to show data in respected addform component inputs when click on edit button?
How to perform Edit operation ?
import React, { useState } from "react";
import Select from "react-select";
const AddForm = (props) => {
const newdata = props.editdata;
const [id, setId] = React.useState(newdata["id"]?newdata.id:"");
const [name, setName] = React.useState(newdata["name"]?newdata.name:"");
const [gender, setGender] = React.useState(()=>{
let _gender= newdata["gender"]?.toLowerCase() || ""
let id_ = props.List.filter( x => {return x["label"]?.toLowerCase() ===_gender } ) ||""
console.log(id_)
return id_[0]["label"]
});
console.log(gender)
return (
<tr>
<td>
<input
type="text"
value={id}
onChange={(e) => {
setId(e.target.value);
}}
></input>
</td>
<td>
<input
type="text"
value={name}
onChange={(e) => {
setName(e.target.value);
}}
></input>
</td>
<td>
<Select options={props.List} value={gender} onChange={setGender} />
</td>
<td>
<button
onClick={(e) => {
props.addRow({
id: id,
name: name,
genderId: gender.value,
gender: gender.label
});
setId("");
setName("");
setGender("");
}}
>
Add
</button>
</td>
</tr>
);
};
const List = [
{
value: 1,
label: "Male"
},
{ value: 2, label: "Female" }
];
const App = (props) => {
const [data, setData] = React.useState([]);
const [edit, isEdit] = useState(false);
const [editdata, setEditData] = useState([]);
return (
<div>
<table>
<tr>
<th>Id</th>
<th>Name</th>
<th>Gender</th>
<th>Action</th>
</tr>
{data &&
data.map((row, idx) => {
return (
<tr key={idx}>
<td>{row.id}</td>
<td>{row.name}</td>
<td>{row.gender}</td>
<td>
<button
onClick={(e) => {
let _data = data.filter((item) => {
return item.id !== row.id;
});
setData(_data);
}}
>
Delete
</button>
</td>
<td>
<button
onClick={(e) => {
// isEdit(true);
setEditData(row);
// console.log(editdata);
<AddForm />;
}}
>
Edit
</button>
</td>
</tr>
);
})}
<AddForm
data={data}
List={List}
setData={setData}
editdata={editdata}
addRow={(e) => {
setData([...data, e]);
}}
/>
</table>
</div>
);
};
export default App;

Related

Can't edit in td input of table in Reactjs

I have two component here Addform (Childcomponent)and App component(parent) I have perform row add and delete operation Why my edit doesn't works ?I have pass the specific row value on which edit has to perform in td input element but I can't perform a onChange event on td input and how to update the data on specific row? How edit can be implement Here?
code
import React, { useState } from "react";
import Select from "react-select";
const AddForm = (props) => {
const newdata = props.editdata;
const [id, setId] = React.useState("");
const [name, setName] = React.useState("");
const [gender, setGender] = React.useState("");
console.log(gender);
return (
<tr>
<td>
<input
type="text"
value={id}
onChange={(e) => {
setId(e.target.value);
}}
></input>
</td>
<td>
<input
type="text"
value={name}
onChange={(e) => {
setName(e.target.value);
}}
></input>
</td>
<td>
<Select options={props.List} value={gender} onChange={setGender} />
</td>
<td>
<button
onClick={(e) => {
props.addRow({
id: id,
name: name,
genderId: gender.value,
gender: gender.label
});
setId("");
setName("");
setGender("");
}}
>
Add
</button>
</td>
</tr>
);
};
const List = [
{
value: 1,
label: "Male"
},
{ value: 2, label: "Female" }
];
const App = (props) => {
const [data, setData] = React.useState([]);
const [edit, isEdit] = useState(false);
const [editdata, setEditData] = useState([]);
const [id, setId] = React.useState(editdata.id || "");
const [name, setName] = React.useState(editdata.name || "");
const [gender, setGender] = React.useState(editdata.gender || "");
const editRow = (e) => {
setData({ ...data, e });
};
return (
<div>
<table>
<tr>
<th>Id</th>
<th>Name</th>
<th>Gender</th>
<th>Action</th>
</tr>
{data &&
data.map((row, idx) => {
if (edit === idx) {
return (
<tr key={idx}>
<td>
<input
type="text"
value={editdata.id}
onChange={(e) => {
setId(e.target.value);
}}
></input>
</td>
<td>
<input
type="text"
value={editdata.name}
onChange={(e) => {
setName(e.target.value);
}}
></input>
</td>
<td>
<Select
options={List}
value={editdata.gender}
onChange={setGender}
/>
</td>
<td>
{" "}
<button
onClick={(e) => {
editRow({
id: id,
name: name,
genderId: gender.value,
gender: gender.label
});
}}
>
save
</button>
</td>
</tr>
);
} else {
return (
<tr key={idx}>
<td>{row.id}</td>
<td>{row.name}</td>
<td>{row.gender}</td>
<td>
<button
onClick={(e) => {
let _data = data.filter((item) => {
return item.id !== row.id;
});
setData(_data);
}}
>
Delete
</button>
</td>
<td>
<button
onClick={(e) => {
isEdit(idx);
setEditData(row);
// console.log(editdata);
<AddForm />;
}}
>
Edit
</button>
</td>
</tr>
);
}
})}
<AddForm
data={data}
List={List}
setData={setData}
editdata={editdata}
addRow={(e) => {
setData([...data, e]);
}}
/>
</table>
</div>
);
};
export default App
;

Edit table row data in td with input in Reactjs

As beginner in Reactjs , I have two component here Addform (Childcomponent)and App component(parent) I have perform row add and delete operation Here.Why my edit doesn't works ?I have pass the specific row value on which edit has to perform in td input element but i can't perform a onChange event on td input and how to update the data on specific row? How edit can be implement Here? So ,far what I done is given below:
demo code sand box
**code**
import React, { useState } from "react";
import Select from "react-select";
const AddForm = (props) => {
const newdata = props.editdata;
const [id, setId] = React.useState("");
const [name, setName] = React.useState("");
const [gender, setGender] = React.useState("");
console.log(gender);
return (
<tr>
<td>
<input
type="text"
value={id}
onChange={(e) => {
setId(e.target.value);
}}
></input>
</td>
<td>
<input
type="text"
value={name}
onChange={(e) => {
setName(e.target.value);
}}
></input>
</td>
<td>
<Select options={props.List} value={gender} onChange={setGender} />
</td>
<td>
<button
onClick={(e) => {
props.addRow({
id: id,
name: name,
genderId: gender.value,
gender: gender.label
});
setId("");
setName("");
setGender("");
}}
>
Add
</button>
</td>
</tr>
);
};
const List = [
{
value: 1,
label: "Male"
},
{ value: 2, label: "Female" }
];
const App = (props) => {
const [data, setData] = React.useState([]);
const [edit, isEdit] = useState(false);
const [editdata, setEditData] = useState([]);
const [id, setId] = React.useState(editdata.id || "");
const [name, setName] = React.useState(editdata.name || "");
const [gender, setGender] = React.useState(editdata.gender || "");
const editRow = (e) => {
setData({ ...data, e });
};
return (
<div>
<table>
<tr>
<th>Id</th>
<th>Name</th>
<th>Gender</th>
<th>Action</th>
</tr>
{data &&
data.map((row, idx) => {
if (edit === idx) {
return (
<tr key={idx}>
<td>
<input
type="text"
value={editdata.id}
onChange={(e) => {
setId(e.target.value);
}}
></input>
</td>
<td>
<input
type="text"
value={editdata.name}
onChange={(e) => {
setName(e.target.value);
}}
></input>
</td>
<td>
<Select
options={List}
value={editdata.gender}
onChange={setGender}
/>
</td>
<td>
{" "}
<button
onClick={(e) => {
editRow({
id: id,
name: name,
genderId: gender.value,
gender: gender.label
});
}}
>
save
</button>
</td>
</tr>
);
} else {
return (
<tr key={idx}>
<td>{row.id}</td>
<td>{row.name}</td>
<td>{row.gender}</td>
<td>
<button
onClick={(e) => {
let _data = data.filter((item) => {
return item.id !== row.id;
});
setData(_data);
}}
>
Delete
</button>
</td>
<td>
<button
onClick={(e) => {
isEdit(idx);
setEditData(row);
// console.log(editdata);
<AddForm />;
}}
>
Edit
</button>
</td>
</tr>
);
}
})}
<AddForm
data={data}
List={List}
setData={setData}
editdata={editdata}
addRow={(e) => {
setData([...data, e]);
}}
/>
</table>
</div>
);
};
export default App;

Table with with array of inputs duplicating row previous row when adding new row

I have a table full of text inputs. All the inputs are stored in a React state array (newUserPledges). If I have values in all the text inputs and add a new row, the new row is duplicating the previous row input values. I can't see why it would be doing that.
Here is my component with all the irrelevant code dotted out.
import React, { useEffect, useState } from 'react';
...
const initialNewPledgeState = {
campaign: '',
date: dateFormatted(new Date()),
pledges: 0,
howPaid: '',
confirmation: '',
sponsor: '',
notes: ''
};
const buttonRef = React.createRef();
const AdminControlPanel = () => {
...
const [addPledgeOptions, setAddPledgeOptions] = useState([]);
const [selectedDeleteUser, setSelectedDeleteUser] = useState('');
const [selectedEditUser, setSelectedEditUser] = useState('');
const [selectedPledgeUser, setSelectedPledgeUser] = useState('');
const [selectedAddPledgeUser, setSelectedAddPledgeUser] =
useState('');
const [allUsers, setAllUsers] = useState([]);
const [usersWithPledges, setUsersWithPledges] = useState([]);
const [usersWithPledgesCount, setUsersWithPledgesCount] =
useState(0);
const [userPledges, setUserPledges] = useState([]);
const [newUserPledges, setNewUserPledges] = useState([
initialNewPledgeState
]);
const alert = useAlert();
const setUpUsersArrays = () => {
getUsers('user').then((r) => {
setAllUsers(r.data.users);
const firstAddPledgeOption = [
{ value: '', label: 'Select a user to add pledges for...' }
];
const usersOptions = r.data?.users?.map((u) => {
return {
value: u.email,
label: `${u.email} - ${u.last_name}, ${u.first_name}`
};
});
if (usersOptions?.length) {
setAddPledgeOptions(
firstAddPledgeOption.concat(usersOptions)
);
} else {
setOptions([]);
setEditOptions([]);
}
});
getUsersWithPledges().then((r) => {
const firstPledgeOption = [
{ value: '', label: 'Select a user to view pledges for...' }
];
const usersOptions = r.data?.users?.map((u) => {
return {
value: u.email,
label: `${u.email} - ${u.last_name}, ${u.first_name}`
};
});
if (usersOptions) {
setUsersWithPledgesCount(usersOptions.length);
setUsersWithPledges(firstPledgeOption.concat(usersOptions));
}
});
};
useEffect(() => {
getDatabaseStats().then((r) => {
setDbStats(r.data.stats);
});
setUpUsersArrays();
}, []);
useEffect(() => {
console.log(selectedDeleteUser.value);
}, [selectedDeleteUser]);
...
const handlePledgeChange = (e, i) => {
// console.log(e.target);
const value = e.target.value;
const pledge = newUserPledges[i];
console.log({ pledge });
pledge[e.target.name] = value;
const tempPledges = [...newUserPledges];
tempPledges[i][e.target.name] = value;
// tempPledges.splice(i, 1, pledge);
setNewUserPledges(tempPledges);
// const value = e.target.value;
// setInputState({
// ...inputState,
// [e.target.name]: value
// });
};
const addNewPledgeRow = (e) => {
e.preventDefault();
const tempPledges = [...newUserPledges].concat(
initialNewPledgeState
);
console.log({ tempPledges });
setNewUserPledges(tempPledges);
};
const deletePledgeRow = (e) => {
e.preventDefault();
const tempPledges = [...newUserPledges];
tempPledges.pop();
setNewUserPledges(tempPledges);
};
const customStyles = {
menuList: (base) => ({
...base,
// kill the white space on first and last option
padding: 0,
minHeight: '300px'
})
};
return (
<div className={'container admin'}>
<h2>Admin Control Panel</h2>
...
<div
className={
'col-12 col-md-9 mx-auto my-4 p-1 border border-secondary bg-light accordion'
}
id={'admin-accordion-add-pledges'}
>
<div className={'accordion-item'}>
<h2 className={'accordion-header'} id={'headingAddPledges'}>
<button
className={'accordion-button collapsed'}
type={'button'}
data-bs-toggle={'collapse'}
data-bs-target={'#collapseAddPledges'}
aria-expanded={'true'}
aria-controls={'collapseAddPledges'}
>
<h4 className={'text-center'}>Add Pledges For User</h4>
</button>
</h2>
<div
id={'collapseAddPledges'}
className={'accordion-collapse collapse mt-1 px-2'}
aria-labelledby={'headingAddPledges'}
data-bs-parent={'#admin-accordion-add-pledges'}
>
{!!addPledgeOptions.length ? (
<Select
className={'mb-2'}
value={selectedAddPledgeUser}
onChange={(e) => setSelectedAddPledgeUser(e)}
options={addPledgeOptions}
styles={customStyles}
/>
) : (
<h4 className={'text-center'}>
No users to add pledges for
</h4>
)}
{selectedAddPledgeUser?.value?.length > 0 && (
<form>
<div className={'my-2 user-pledges'}>
<table className={'table table-bordered'}>
<thead>
<tr>
<th width={100}>Campaign</th>
<th width={120}>Date</th>
<th width={80}>Pledges</th>
<th>How Paid</th>
<th>Confirmation</th>
<th>Sponsor</th>
<th>Notes</th>
</tr>
</thead>
<tbody>
{!!newUserPledges.length &&
newUserPledges.map((p, i) => (
<tr key={i}>
<td>
<input
type={'text'}
className={'form-control'}
value={p.campaign}
name={'campaign'}
id={`campaign-${i}`}
onChange={(e) =>
handlePledgeChange(e, i)
}
/>
</td>
<td>
<input
type={'date'}
max={dateFormatted(new Date())}
className={'form-control'}
value={p.date}
name={'date'}
id={`date-${i}`}
onChange={(e) =>
handlePledgeChange(e, i)
}
/>
</td>
<td>
<input
type={'text'}
className={'form-control'}
value={p.pledges}
name={'pledges'}
onChange={(e) =>
handlePledgeChange(e, i)
}
/>
</td>
<td>
<input
type={'text'}
className={'form-control'}
value={p.howPaid}
name={'howPaid'}
onChange={(e) =>
handlePledgeChange(e, i)
}
/>
</td>
<td>
<input
type={'text'}
className={'form-control'}
value={p.confirmation}
name={'confirmation'}
onChange={(e) =>
handlePledgeChange(e, i)
}
/>
</td>
<td>
<input
type={'text'}
className={'form-control'}
value={p.sponsor}
name={'sponsor'}
onChange={(e) =>
handlePledgeChange(e, i)
}
/>
</td>
<td>
<input
type={'text'}
className={'form-control'}
value={p.notes}
name={'notes'}
onChange={(e) =>
handlePledgeChange(e, i)
}
/>
</td>
</tr>
))}
</tbody>
</table>
<div className={'d-flex justify-content-evenly'}>
<button
className={'btn btn-primary'}
onClick={addNewPledgeRow}
disabled={newUserPledges.length > 9}
>
<FontAwesomeIcon icon={faPlusSquare} />
Add New Row
</button>
<button
className={'btn btn-primary'}
onClick={deletePledgeRow}
disabled={newUserPledges.length === 1}
>
<FontAwesomeIcon icon={faMinusSquare} />
Delete Row
</button>
<button className={'btn btn-success'}>
Submit Pledges
</button>
<button className={'btn btn-danger'}>
Reset Table
</button>
</div>
</div>
</form>
)}
</div>
</div>
</div>
<br />
</div>
);
};
export default AdminControlPanel;
Here is an example of what is happening. I fill in values in the first row, and then hit add row and it adds a second row with duplicated values.
Asked my question in the Reactiflux Discord and got an answer right away. I was mutating my rows state in the handlePledgeChange function.
I have changed that function to this and it works great now.
const handlePledgeChange = (e, i) => {
const value = e.target.value;
const tempPledges = newUserPledges.map((item, idx) => {
if (i === idx) return { ...item, [e.target.name]: value };
return item;
});
setNewUserPledges(tempPledges);
};

Select rows issue in pagination react table

I've made a table with one column as checkbox to select that row. So if the user checks this row's checkbox, I'll add isChecked : true property in state and on uncheck will change isChecked: false of that in state. Each page is having 10rows. The issue is when I checked the 1st row checkbox of 1st page and when I go to Next Page somehow the 1st row of next page checkbox also appears checked. However only 1st row is set to true in state. Whats the issue? What wrong I'm doing can anyone tell? Thanks in advance!
import React,{Component} from 'react';
import { Table,Button,Input } from 'reactstrap';
import SelectedUsers from './SelectedUsers';
import { yellow } from '#material-ui/core/colors';
import Icon from '#material-ui/core/Icon';
class Users extends Component {
constructor(props) {
super(props);
this.state = {
users : [],
pageSize: 10,
pageIndex: 0,
selectedUsers : [],
filterCandidate : '',
searchVal : ""
};
}
componentDidMount() {
const userLink = 'api';
fetch(userLink, {
method: 'GET'
})
.then(res => res.json())
.then(data => {
this.setState({
users : data
})
console.log(data)
})
}
onSelectUser = (e,i) => {
const copy_users = this.state.users.slice() ;
const checked = e.target.checked
copy_users[i].isChecked = checked
this.setState({ copy_users})
// console.log( e.target.value)
}
handlePrevPageClick = (event) => {
this.setState(prevState => ({
pageIndex: prevState.pageIndex > 0 ? prevState.pageIndex - 1 : 0
}));
}
handleNextPageClick = (event) => {
this.setState(prevState => ({
pageIndex:
prevState.pageIndex <
Math.floor(prevState.users.length / prevState.pageSize)
? prevState.pageIndex + 1
: prevState.pageIndex
}));
}
render() {
let profile = 'Profile Image';
return (
<div className="bets_page">
<Table striped responsive>
<thead>
<tr>
<th>Select</th>
<th>Player Name</th>
<th>Level<Icon style={{ color: yellow[800] }} fontSize="small">star</Icon></th>
<th>Avatar</th>
<th>BET</th>
<th>Wins<Icon style={{ color: yellow[800] }} fontSize="small">euro</Icon></th>
<th>Lost</th>
<th>Price</th>
</tr>
</thead>
<tbody>
{this.state.users.slice(
this.state.pageIndex * this.state.pageSize,
this.state.pageIndex * this.state.pageSize + this.state.pageSize
).map((data,i) => (
<tr key={i}>
<td>
<label className="checkbox">
<input type="checkbox"
checked={data.isChecked}
key={i}
value={data.Name}
onChange={(e) => this.onSelectUser(e,i)}/>
</label>
</td>
<td>{data.Name}</td>
<td></td>
<td><img src={data[profile]} alt={data.Name}
className="avatar"/></td>
<td>{data.Bet}</td>
<td></td>
<td></td>
<td>{data.Price}</td>
</tr>
))}
</tbody>
</Table>
<div>
<Button onClick={event => this.handlePrevPageClick(event)} className="m-2">
{"<"}
</Button>Page {this.state.pageIndex+1}
<Button onClick={event => this.handleNextPageClick(event)} className="m-2">
{">"}
</Button>
</div>
</div>
}
}
export default Users;
when you slice the users and apply map on them the 'i' variable starts from 0 for each page. you should add 'this.state.pageIndex * this.state.pageSize' to 'i' variable whenever you set it for key and you send that to onSelectUser
render() {
return (
<div className="bets_page">
<Table striped responsive>
<thead>
<tr>
<th>Select</th>
<th>Player Name</th>
</tr>
</thead>
<tbody>
{this.state.users
.slice(
this.state.pageIndex * this.state.pageSize,
this.state.pageIndex * this.state.pageSize + this.state.pageSize
)
.map((data, i) => {
const index = i + this.state.pageIndex * this.state.pageSize;
return (
<tr key={index}>
<td>
<label className="checkbox">
<input
type="checkbox"
checked={data.isChecked}
key={i}
value={data.Name}
onChange={(e) => this.onSelectUser(e, index)}
/>
</label>
</td>
<td>{data.Name}</td>
</tr>
);
})}
</tbody>
</Table>
<div>
<Button
onClick={(event) => this.handlePrevPageClick(event)}
className="m-2"
>
{"<"}
</Button>
Page {this.state.pageIndex + 1}
<Button
onClick={(event) => this.handleNextPageClick(event)}
className="m-2"
>
{">"}
</Button>
</div>
</div>
);
}
I simplified your code and I created the online demo here

React: Proper way to update an array of objects in state

I am a professional web developer teaching myself react. I created this table as part of a larger form.
The table is invoked inside the form component
<ProductList
products={this.state.products}
onChange={products => this.sendUpdate('products', products)}
/>
this.sendUpdate:
sendUpdate(field, value) {
this.setState({[field]: value});
socket.emit('updateItem', this.state.id, {[field]: value});
}
That part is all working great with all my form updates. but now I am trying to figure out how to process the updates inside the table. Each product is a row of the table invoked like this:
<tbody>
{this.props.products.map((product, i) =>
<Product key={i} data={product} products={this}/>
)}
</tbody>
What is the proper way to update the state when I type in one of the inputs?
<FormControl
value={this.props.data.species}
onClick={e => this.updateProduct('species', e.target.value)}
/>
full code for ProductList
import React from "react";
import {Button, Table, FormControl} from "react-bootstrap";
class Product extends React.Component {
updateField(...props){
this.props.products.updateProduct(this.data, ...props)
}
render() {
return (
<tr>
<td>
<FormControl
value={this.props.data.species}
onClick={e => this.updateProduct('species', e.target.value)}
/>
</td>
<td><FormControl/></td>
<td><FormControl/></td>
<td><FormControl/></td>
<td><FormControl/></td>
<td><FormControl/></td>
<td><FormControl type="number"/></td>
<td><Button bsStyle="danger" onClick={() => this.props.products.deleteProduct(this.props.data)}>X</Button></td>
</tr>
);
}
}
export default class ProductList extends React.Component {
constructor(...props) {
super(...props);
}
addProduct() {
let products = this.props.products.concat([{timestamp: Date.now()}]);
this.props.onChange(products);
}
updateProduct(product, field, newValue) {
this.props.products;
// ???
}
deleteProduct(product) {
let products = this.props.products.filter(p => {
return p !== product
});
this.props.onChange(products);
}
render() {
return (
<Table responsive>
<thead>
<tr>
<th>Species</th>
<th>Dried</th>
<th>Cut</th>
<th>Dimensions Green</th>
<th>Dimensions Dry</th>
<th>Color</th>
<th>Quantity</th>
<th className="text-right">
<Button bsStyle="success" bsSize="xsmall" onClick={() => this.addProduct()}>Add</Button>
</th>
</tr>
</thead>
<tbody>
{this.props.products.map(product => <Product key={product.timestamp} data={product} products={this}/>)}
</tbody>
</Table>
);
}
}
This is what I ended up with based on the accepted answer:
import React from "react";
import {Button, Table, FormControl} from "react-bootstrap";
export default class ProductList extends React.Component {
constructor(...props) {
super(...props);
}
addProduct() {
let products = this.props.products.concat([{}]);
this.props.onChange(products);
}
updateProduct(product, field, newValue) {
const products = this.props.products.map(p => {
return p === product ? {...p, [field]: newValue} : p;
});
this.props.onChange(products);
}
deleteProduct(product) {
let products = this.props.products.filter(p => {
return p !== product
});
this.props.onChange(products);
}
render() {
return (
<Table responsive striped>
<thead>
<tr>
<th>Species</th>
<th>Dried</th>
<th>Cut</th>
<th>Dimensions Green</th>
<th>Dimensions Dry</th>
<th>Color</th>
<th>Quantity</th>
<th className="text-right">
<Button bsStyle="success" bsSize="xsmall" onClick={() => this.addProduct()}>Add</Button>
</th>
</tr>
</thead>
<tbody>
{this.props.products.map((product, i) => this.renderRow(i, product, this))}
</tbody>
</Table>
);
}
renderRow(i, product) {
return (
<tr key={i}>
<td>
<FormControl
value={product.species || ''}
onChange={e => this.updateProduct(product, 'species', e.target.value)}
/>
</td>
<td>
<FormControl
value={product.dried || ''}
onChange={e => this.updateProduct(product, 'dried', e.target.value)}
/>
</td>
<td>
<FormControl
value={product.cut || ''}
onChange={e => this.updateProduct(product, 'cut', e.target.value)}
/>
</td>
<td>
<FormControl
value={product.dimensionsGreen || ''}
onChange={e => this.updateProduct(product, 'dimensionsGreen', e.target.value)}
/>
</td>
<td>
<FormControl
value={product.dimensionsDry || ''}
onChange={e => this.updateProduct(product, 'dimensionsDry', e.target.value)}
/>
</td>
<td>
<FormControl
value={product.color || ''}
onChange={e => this.updateProduct(product, 'color', e.target.value)}
/>
</td>
<td>
<FormControl
type="number"
value={product.quantity || 0}
onChange={e => this.updateProduct(product, 'quantity', e.target.value)}
/>
</td>
<td><Button bsStyle="danger" onClick={() => this.deleteProduct(product)}>X</Button></td>
</tr>
);
}
}
In your ProductsList's render(), change the array map to something like:
{this.props.products.map((product, index) => <Product key={product.timestamp} data={product} index={index} products={this}/>)}
Then in your Product's change the updateField() to:
updateField(...props){
this.props.products.updateProduct(this.props.index, ...props)
}
And finally, change ProductsList's updateProduct() to:
updateProduct(index, field, newValue) {
const products = this.props.products.map((product, productIndex)) => {
if (index === productIndex) {
return {
...product,
[field]: newValue
};
}
return product;
})
this.props.onChange(products);
}
Also, there's a slight typo in Product render. The FormControl's onClick should read onClick={e => this.updateField('species', e.target.value)}.

Resources