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

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)}.

Related

CRUD operation on dynamic form 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;

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

Redux - 'map function' is not rendered after props changed but 'input value' is rendered

For example, the below one is rendered without any issues in redux.
<Input type="textarea" value={this.props.description}
onChange={this.descriptionChange}/>
But, this one is never rendered after 'props.permissions' is changed. Definitely the redux util in Chrome indicates 'props.permissions' is already changed.
</tr>
</thead>
<tbody> {
this.props.permissions.map((permission, i) => (
<tr className={'text-center'} key={i}>
<td>
<Input type={"checkbox"}/>
</td>
<td>
<div> {permission.id}</div>
</td>
<td>
<div>{permission.module_value}</div>
</td>
<td>
<div>{permission.name}</div>
</td>
<td>
<div>{permission.uri}</div>
</td>
<td>
<div>{permission.description}</div>
</td>
</tr>
))
}
I am aware that if I use 'setState' instead of 'redux', the map function re-renders the screen.
Also here comes the full code.
import React, {Component} from 'react';
import {Route, Link} from 'react-router-dom';
import {
Table,
Pagination,
PaginationItem,
PaginationLink,
Row,
Col,
Form,
FormGroup,
Label,
Collapse,
Card,
CardHeader,
CardBody,
TabContent,
TabPane,
DropdownToggle,
DropdownMenu,
DropdownItem,
Button,
Input,
InputGroup,
InputGroupAddon,
InputGroupText,
InputGroupButtonDropdown
} from 'reactstrap';
import Axios from 'axios';
import {connect} from 'react-redux';
import {FIELD_GROUP_PERMISSION, FIELD_PERMISSION_LISTS} from '../../../../../actions/permission';
class Register extends Component {
constructor(props) {
super(props);
this.state = {
pSelected: [],
splitButtonOpen: false,
isOpen: false,
collapse: true,
listDate: [
{listName: "abc"},
{listName: "qed"}
],
listModule: [
{item: "default1"},
{item: "default2"},
{item: "default3"},
],
listCounter: [
{counter: 100},
{counter: 500},
{counter: 1000},
]
,
permissions: [
],
moduleList: [
{
name: "모두",
value: 'all',
},
{
name: "웹",
value: 'web',
},
{
name: "네이티브",
value: 'native'
}
]
}
this.moduleChange = ev => this.props.moduleChange(ev.target.value);
this.nameChange = ev => this.props.nameChange(ev.target.value);
this.descriptionChange = ev => this.props.descriptionChange(ev.target.value);
this.doRegister = this.doRegister.bind(this);
}
render() {
return (
<div className={'bg-light'}>
<Card>
<CardHeader className={'font-weight-bold'}>그룹 권한 등록</CardHeader>
<CardBody>
<Form>
<FormGroup row>
<Label for={"selectModule"} sm={2}>Module Select</Label>
<Col sm={10}>
<select onChange={this.moduleChange} value={this.props.module}
id="pageCounter">
{this.state.moduleList.map((module, i) => (
<option key={i}
value={module.value}
>{module.name}</option>
))}
</select>
</Col>
</FormGroup>
<FormGroup>
<Label for={"gName"}>Group Name</Label>
<Input type={"text"} name={"gName"} id={"gName"}
placeholder={"Input Group Name...."} value={this.props.name}
onChange={this.nameChange}/>
</FormGroup>
<FormGroup>
<Label for={"gDesc"}>Group Desc</Label>
<Input type={"textarea"} name={"gDesc"} id={"gDesc"} value={this.props.description}
onChange={this.descriptionChange}/>
</FormGroup>
<FormGroup>
<div>
<Table hover responsive
className="table-outline mb-0 d-none d-sm-table">
<thead className="thead-light">
<tr className={'text-center'}>
<th>
<InputGroup>
<InputGroupAddon addonType={"prepend"}>
<InputGroupText>
<Input addon type={"checkbox"}
className={"bg-light"}/>
</InputGroupText>
</InputGroupAddon>
<span>Select</span>
</InputGroup>
</th>
<th>ID</th>
<th>Module</th>
<th>Name</th>
<th>Uri</th>
<th>Description</th>
</tr>
</thead>
<tbody>
{
this.props.permissions.map((permission, i) => (
<tr className={'text-center'} key={i}>
<td>
<Input type={"checkbox"}/>
</td>
<td>
<div> {permission.id}</div>
</td>
<td>
<div>{permission.module_value}</div>
</td>
<td>
<div>{permission.name}</div>
</td>
<td>
<div>{permission.uri}</div>
</td>
<td>
<div>{permission.description}</div>
</td>
</tr>
))
}
</tbody>
</Table>
<nav className={"mt-3 w-100"}>
<Pagination className={"justify-content-end"}>
<PaginationItem disabled>
<PaginationLink previous href="#"/>
</PaginationItem>
<PaginationItem active>
<PaginationLink href="#">
1
</PaginationLink>
</PaginationItem>
<PaginationItem>
<PaginationLink href="#">
2
</PaginationLink>
</PaginationItem>
<PaginationItem>
<PaginationLink href="#">
3
</PaginationLink>
</PaginationItem>
<PaginationItem>
<PaginationLink href="#">
4
</PaginationLink>
</PaginationItem>
<PaginationItem>
<PaginationLink href="#">
5
</PaginationLink>
</PaginationItem>
<PaginationItem>
<PaginationLink next href="#"/>
</PaginationItem>
</Pagination>
</nav>
</div>
</FormGroup>
<FormGroup className={'float-right'}>
<Button color={'danger'} className={'float-right'} onClick={this.doRegister}>등록</Button>
</FormGroup>
</Form>
</CardBody>
</Card>
</div>
);
}
componentWillMount() {
Axios.get('/api/indexPermissions?module=' + this.state.moduleList[0].value).then(response => {
if (response.data.success === 1) {
this.props.permissionsChange(response.data.permissions);
this.forceUpdate();
}
}).catch(error => {
console.log(error);
alert(error);
});
}
componentWillReceiveProps(nextProps) {
/* if (nextProps['permissions'] !== this.props.permissions) {
this.props.permissionsChange(response.data.permissions);
}*/
/*
console.log(nextProps);
if (this.props.permissions) {
console.log(nextProps);
if (nextProps.permissions !== this.permissions) {
alert('aaa');
}
}
*/
}
doRegister() {
console.log(this.props);
}
}
Register.defaultProps = {
permissions: []
};
/* reducer, redux */
let mapStateToProps = (state) => {
return {
...state
};
}
let mapDispatchToProps = (dispatch) => {
return {
moduleChange: (module) => {
dispatch({type: FIELD_GROUP_PERMISSION, key: 'module', value: module})
},
nameChange: (name) => {
dispatch({type: FIELD_GROUP_PERMISSION, key: 'name', value: name})
},
descriptionChange: (description) => {
dispatch({type: FIELD_GROUP_PERMISSION, key: 'description', value: description})
},
permissionsChange: (permissions) => {
dispatch({type: FIELD_PERMISSION_LISTS, key: 'permissions', value: permissions})
}
}
}
Register = connect(mapStateToProps, mapDispatchToProps)(Register);
export default Register;
The following is the Redux code.
import { FIELD_GROUP_PERMISSION, FIELD_PERMISSION_LISTS } from '../../actions/permission';
export default (state = {}, action) => {
switch(action.type) {
case FIELD_GROUP_PERMISSION:
return { ...state, [action.key]: action.value };
case FIELD_PERMISSION_LISTS:
return { ...state, [action.key]: action.value };
default:
return state;
}
}

How to circumvent material ui radio button limitation of being placed in a parent wrapping element?

I have the following react component:
import React, { Component } from 'react';
import classes from './generalinfo.css';
import { Link } from 'react-router-dom';
import { connect } from 'react-redux';
import { RadioButton, RadioButtonGroup } from 'material-ui/RadioButton';
class GeneralInfo extends Component {
_ToggleNextScreenButton = (e) => {
let currentState = this.props.infoObj;
let checkboxStatus = Object.keys(currentState).map( (value) => {
return currentState[value];
});
let ArroyOfCheckboxValues = checkboxStatus.filter((value) => {
return value === false;
});
if(ArroyOfCheckboxValues.length > 0) {
e.preventDefault();
}
}
render() {
return (
<div className={ classes.screen2 } >
<table className={ classes.initial__survey__details__table }>
<thead>
<tr>
<td>
Gender
</td>
<td>
Age
</td>
</tr>
</thead>
<tbody>
<tr>
<td>
<input type="radio" name="genderRadio" value="male"
onChange={ (e) => { this.props.validateRadioInput({
name : e.target.getAttribute('name'),
value : e.target.getAttribute('value')
}) }
} />
<label>Male</label>
</td>
<td>
<input type="radio" name="ageRadio" value="Less than 35"
onChange={ (e) => { this.props.validateRadioInput({
name : e.target.getAttribute('name'),
value : e.target.getAttribute('value')
}) } } />
<label>Less than 35</label>
</td>
</tr>
<tr>
<td>
<input type="radio" name="genderRadio" value="Female"
onChange={ (e) => { this.props.validateRadioInput({
name : e.target.getAttribute('name'),
value : e.target.getAttribute('value')
}) } } />
<label>Female</label>
</td>
<td>
<input type="radio" name="ageRadio" value="More than 35"
onChange={ (e) => { this.props.validateRadioInput({
name : e.target.getAttribute('name'),
value : e.target.getAttribute('value')
}) } } />
<label>More than 35</label>
</td>
</tr>
<tr>
<td colSpan="2">
<Link to="/preferences" className={ [classes.btn , classes["btn--fullwidth"] , classes.btn__next ].join(' ') }
onClick={ (e) => this._ToggleNextScreenButton(e) } >
Next
</Link>
</td>
</tr>
</tbody>
</table>
</div>
);
}
}
(unnecessary parts intentionally deleted).
As you can see i have independent radio elements inside a td , now i wanted to add radio element but using material-ui, the problem is all the radio buttons of a specific group have to be grouped under a parent <RadioButtonGroup /> as you can see below:
<RadioButtonGroup name="shipSpeed" defaultSelected="not_light">
<RadioButton
value="light"
label="Simple"
style={styles.radioButton}
/>
<RadioButton
value="not_light"
label="Selected by default"
style={styles.radioButton}
/>
<RadioButton
value="ludicrous"
label="Custom icon"
checkedIcon={<ActionFavorite style={{color: '#F44336'}} />}
uncheckedIcon={<ActionFavoriteBorder />}
style={styles.radioButton}
/>
</RadioButtonGroup>
How can i circumvent this limitation of the radio button being placed inside a parent wrapper (I.E. i'd like to use the radio button with a parent wrapper ) and still use material-ui ?
You can write a wrapper for RadioButton and then use that wrapper instead of the original RadioButton:
const TDRadioButton = ({wrapperProps, ...props}) => (
<td {...wrapperProps}>
<RadioButton {...props}>
</td>
);
This will wrap every radio button into a <td> while preserving all of its functionality by forwarding the props.

How to fill select options and filter the second select in FieldArray in Redux Form?

The first select, when selected, should filter the second, or popular through a request to Api.
The problem I'm having is that when entering the second field, the state is shared to the options, and when modifying any field, modifies all the options.
class FieldCentroCusto extends Component {
constructor(){
super()
this.state = {
itensObra: []
}
this.toggleItens = this.toggleItens.bind(this)
}
toggleItens(event) {
this.props.optionsObras.map(obra => {
if (event.target.value === obra.nome) {
return this.setState({
itensObra: obra.itens
})
}
return false
})
}
render() {
const renderItens = ({ fields, optionsObras }) => (
<div>
<Button color="primary" type="button" onClick={() => fields.push({})}>
<i className="fa fa-plus"></i> Adicionar Item de Custo
</Button>
<br /><br />
<table className="table table-bordered table-hover">
<thead className="thead-inverse">
<tr>
<th>Obra</th>
<th>Centro de Custo</th>
</tr>
</thead>
<tbody>
{fields.map((item, itemIndex) =>
<tr key={itemIndex}>
<td>
<Field name={`${item}.obra`} component={LabelAndSelect}
onChange={this.toggleItens} options={
optionsObras.map((option, optionIndex) => {
return {value: `${option.nome === undefined?'':
option.nome}`, label: `${option.nome === undefined?'':
option.nome}`}
}
)} />
</td>
<td>
<Field name={`${item}.itemObra`} component={LabelAndSelect}
options={this.state.itensObra.map((option, optionIndex) => {
return {value: `${option.descricao === undefined?'':
option.descricao}`, label: `${option.descricao === undefined?'':
option.descricao}`}
}
)} />
</td>
</tr>
)}
</tbody>
</table>
</div>
)
return (
<FieldArray name="centrosCusto"
optionsObras={this.props.optionsObras}
component={renderItens} />
)
}
}
I got it sorted out.
I passed the FieldArray index in the onChange event of the selection and in the state where I placed an array with the passed index. So I can fill in the other selection options with specific indexes in the array.
constructor(){
super()
this.state = {
itensObra: []
}
this.toggleItens = this.toggleItens.bind(this)
}
toggleItens(event, index) {
const itens = this.state.itensObra
this.props.optionsObras.map(obra => {
if (event.target.value === obra.nome) {
itens[index] = obra.itens
return this.setState({
itensObra: itens
})
}
return false
})
}
Here are the Fields:
<td>
<Field name={`${item}.obra`} component={LabelAndSelect}
onChange={(event) => this.toggleItens(event, itemIndex)}
options={optionsObras.map((option, optionIndex) => {
return {value: `${option.nome === undefined?'':option.nome}`,
label:`${option.nome === undefined?'':option.nome}`}
}
)} />
</td>
<td>
<Field name={`${item}.itemObra`} component={LabelAndSelect}
options={this.state.itensObra[itemIndex]?
this.state.itensObra[itemIndex].map((option, optionIndex) => {
return {value: `${option.descricao === undefined?'':option.descricao}`,
label: `${option.descricao === undefined?'':option.descricao}`}
}
):[]} />
</td>

Resources