I have built a React table like so:
const Table = ({data}) => {
return (
<table className="table table-bordered">
<thead>
<tr>
<th>Qty</th>
<th>Description</th>
<th>Price (£)</th>
</tr>
</thead>
<tbody>
{data.map((row) => {
return (
<tr>
<td><input type='number' className='form-control' step='1' min="1" value={row[0]}/></td>
<td><input type='text' className='form-control' value={row[1]}/></td>
<td><input type='text' className='form-control' placeholder='6.00' value={row[2]}/></td>
</tr>
);
})}
</tbody>
</table>
);
};
Table.propTypes = {
data: React.PropTypes.array.isRequired
};
export default Table;
In the class I am using this component I am passing data as a parameter (which is initially empty):
materials: [[],[],[],[],[],[],[],[],[],[]] //Initialise with 10 empty rows
<Table data={materials} />
This will build up a table with 10 empty rows. The only problem now is that when I enter data into the table, the data array that I have mapped does not update with the data I have entered.
I think what I need is some event where I can update the data with a snapshot of what has been entered but I am not sure how to implement this. Any help would be greatly appreciated.
React doesn't work with two-way data binding, like Angular JS does, for instance. props
are read-only, so you would need update them where they belong.
For instance, the parente component, where <Table />
is declared could have materials
array in its state and, besides passing materials
as props, it could pass a function handler like onCellChange(row, column)
, so you could bind it with the onChange
events in the inputs elements.
Like so,
const Table = ({data, onCellChange}) => {
return (
<table className="table table-bordered">
<thead>
<tr>
<th>Qty</th>
<th>Description</th>
<th>Price (£)</th>
</tr>
</thead>
<tbody>
{data.map((row, index) => {
return (
<tr key={index}>
<td><input type='number' className='form-control' step='1' min="1" value={row[0]} onChange={() => onCellChange(index, 0)}/></td>
<td><input type='text' className='form-control' value={row[1]} onChange={() => onCellChange(index, 1)}/></td>
<td><input type='text' className='form-control' placeholder='6.00' value={row[2]} onChange={() => onCellChange(index, 2)}/></td>
</tr>
);
})}
</tbody>
</table>
);
};
Table.propTypes = {
data: React.PropTypes.array.isRequired
};
So, at the parent component, you would declare the component like <Table data={this.state.materials} onCellChange={this.onCellChange} />
.
And it would have a method like this:
onCellChange: function(row, column) {
//update the cell with this.setState() method
}
You can achieve this by maintaining state of your table data. I've made a rough structure of how you could do it here: http://codepen.io/PiotrBerebecki/pen/QKrqPO
Have a look at the console output which shows state updates.
class Table extends React.Component {
constructor(props) {
super(props);
this.state = {
materials: props.data
};
}
handleChange(index, dataType, value) {
const newState = this.state.materials.map((item, i) => {
if (i == index) {
return {...item, [dataType]: value};
}
return item;
});
this.setState({
materials: newState
});
}
render() {
console.clear();
console.log(JSON.stringify(this.state.materials));
return (
<table className="table table-bordered">
<thead>
<tr>
<th>Qty</th>
<th>Description</th>
<th>Price (£)</th>
</tr>
</thead>
<tbody>
{this.state.materials.map((row, index) => {
return (
<tr>
<td>
<input onChange={(e) => this.handleChange(index, 'qty', e.target.value)}
type='number'
className='form-control'
step='1' min="1"
value={this.state.materials[index].qty}/>
</td>
<td>
<input onChange={(e) => this.handleChange(index, 'desc', e.target.value)}
type='text'
className='form-control'
value={this.state.materials[index].desc}/>
</td>
<td>
<input onChange={(e) => this.handleChange(index, 'price', e.target.value)}
type='text'
className='form-control'
placeholder='6.00'
value={this.state.materials[index].price}/>
</td>
</tr>
);
})}
</tbody>
</table>
);
}
}
const materials = [
{ qty: '', desc: '', price: '' },
{ qty: '', desc: '', price: '' },
{ qty: '', desc: '', price: '' },
{ qty: '', desc: '', price: '' },
{ qty: '', desc: '', price: '' },
{ qty: '', desc: '', price: '' },
{ qty: '', desc: '', price: '' },
{ qty: '', desc: '', price: '' }
]
ReactDOM.render(<Table data={materials} />, document.getElementById('app'));
you need to update the state onChange:
getInitialState: function() {
return {value: 'Hello!'};
},
handleChange: function(event) {
this.setState({value: event.target.value});
},
render: function() {
return (
<input
type="text"
value={this.state.value}
onChange={this.handleChange}
/>
);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With