React editable table - javascript

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}
/>
);
}

Related

Can't render table rows in functional components, objects are not valid as a react child

Uncaught Error: Objects are not valid as a React child
Here is my RowComponent:
function IssueRow(props) {
const issue = props.issue;
return (
<tr>
<td>{issue.id}</td>
<td>{issue.status}</td>
<td>{issue.owner}</td>
<td>{issue.created}</td>
<td>{issue.effort}</td>
<td>{issue.due}</td>
<td>{issue.title}</td>
</tr>
)
};
Here is my Table Component:
function IssueTable(props) {
const issueRows = props.issues.map(issue => (
<IssueRow key={issue.id} issue={issue} />
))
return (
<table className="bordered-table">
<thead>
<tr>
<td>ID</td>
<td>Status</td>
<td>Owner</td>
<td>Created</td>
<td>Effort</td>
<td>Due Date</td>
<td>Title</td>
</tr>
</thead>
<tbody>
{issueRows}
</tbody>
</table>
)
};
My Table Component is being rendered from a TableList Component with these properties:
this.state = {
issues: [
{ id: 1, status: 'New', owner: 'Ravan', effort: 5, created: new Date('2018-08-15'), due: undefined, title: 'Error in console when clicking Add' },
{ id: 2, status: 'Assigned', owner: 'Eddie', effort: 14, created: new Date('2018-08-16'), due: new Date('2018-08-30'), title: 'Missing bottom border on panel' }
]
}
.
.
.
render() {
return (
<React.Fragment>
<h1>Issue Tracker</h1>
<IssueFilter />
<hr />
<IssueTable issues={this.state.issues} />
<hr />
<IssueAdd createIssue={this.createIssue} />
</React.Fragment>
)
}
I can not figure out, why i am getting that error message. Is it maybe because of some compilation errors ? I am not using npx create-react-app, and set the environment up myself.
issue.created and issue.due are Date objects. You can't use them directly as React elements, you have to convert them to string first, for example by using .toString() method.
function IssueRow(props) {
const issue = props.issue;
return (
<tr>
<td>{issue.id}</td>
<td>{issue.status}</td>
<td>{issue.owner}</td>
<td>{issue.created.toString()}</td>
<td>{issue.effort}</td>
<td>{issue.due && issue.due.toString()}</td>
<td>{issue.title}</td>
</tr>
)
};

how can i add new row my react bootstrap table

I created the table I mentioned below using React js. When I click on the button below the table, I want to add a new row to the table. I have listed the react code I wrote below. how can I do that?
My React Code
const PPP13 = (props) => {
return (
<Jumbotron>
<p className="btn-group">13- List all owners of 20% or more of the equity of the Applicant</p>
<Table striped bordered hover>
<thead>
<tr>
<th>Owner Name</th>
<th>Title</th>
<th>Ownership %</th>
<th>TIN (EIN, SSN)</th>
<th>Address</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<FormControl aria-label="DDD"/>
</td>
<td>
<FormControl aria-label="DDD"/>
</td>
<td>
<FormControl aria-label="DDD"/>
</td>
<td>
<FormControl aria-label="DDD"/>
</td>
<td>
<FormControl aria-label="DDD"/>
</td>
</tr>
</tbody>
</Table>
<Button className="btn-group" name="add" value="No">
Add more owners
</Button>
</Jumbotron>
)
}
Here is what you can do. Lets say you have a Main component which will get all details.
class Products extends React.Component {
constructor(props) {
super(props);
// this.state.products = [];
this.state = {};
this.state.filterText = "";
this.state.products = [
{
id: 1,
category: 'Sporting Goods',
price: '49.99',
qty: 12,
name: 'football'
}, {
id: 2,
category: 'Sporting Goods',
price: '9.99',
qty: 15,
name: 'baseball'
}, {
id: 3,
category: 'Sporting Goods',
price: '29.99',
qty: 14,
name: 'basketball'
}, {
id: 4,
category: 'Electronics',
price: '99.99',
qty: 34,
name: 'iPod Touch'
}, {
id: 5,
category: 'Electronics',
price: '399.99',
qty: 12,
name: 'iPhone 5'
}, {
id: 6,
category: 'Electronics',
price: '199.99',
qty: 23,
name: 'nexus 7'
}
];
}
handleAddEvent(evt) {
var id = (+ new Date() + Math.floor(Math.random() * 999999)).toString(36);
var product = {
id: id,
name: "empty row",
price: "mpty row",
category: "mpty row",
qty: 0
}
this.state.products.push(product);
this.setState(this.state.products);
}
handleProductTable(evt) {
var item = {
id: evt.target.id,
name: evt.target.name,
value: evt.target.value
};
var products = this.state.products.slice();
var newProducts = products.map(function(product) {
for (var key in product) {
if (key == item.name && product.id == item.id) {
product[key] = item.value;
}
}
return product;
});
this.setState({products:newProducts});
};
render() {
return (
<div>
<ProductTable onProductTableUpdate={this.handleProductTable.bind(this)} onRowAdd={this.handleAddEvent.bind(this)} products={this.state.products} />
</div>
);
}
}
This contains the code for adding row.Then for the table do something like this.
class ProductTable extends React.Component {
render() {
var onProductTableUpdate = this.props.onProductTableUpdate;
var product = this.props.products.map(function(product) {
return (<ProductRow onProductTableUpdate={onProductTableUpdate} product={product} key={product.id}/>)
});
return (
<div>
<button type="button" onClick={this.props.onRowAdd} className="btn btn-success pull-right">Add</button>
<table className="table table-bordered">
<thead>
<tr>
<th>Name</th>
<th>price</th>
<th>quantity</th>
<th>category</th>
</tr>
</thead>
<tbody>
{product}
</tbody>
</table>
</div>
);
}
}
Now for the row Comoponent:
class ProductRow extends React.Component {
render() {
return (
<tr className="eachRow">
<td>
{this.props.product.id}
</td>
<td>
{this.props.product.price}
</td>
<td>
{this.props.product.qty}
</td>
<td>
{this.props.product.category}
</td>
</tr>
);
}
}
Working Example:
https://jsfiddle.net/mrAhmedkhan/nvgozjhy/
Ok here's my plan:
First we create a state to hold all the data for the table. I've used an object instead of an array as it's much easier to do the change handling. With arrays you always end up doing all this awkward splicing. You can always parse the object out into an array when you're ready to use it elsewhere.
Then we render out each row of the table by mapping over the entries in our table state. Note we also write the change handler inside the map, meaning we can easily use the rowId (tableData key) to set our new state when a change comes in.
Finally we plop in a button to add more rows. This has a click handler associated with it (handleAddRowClick) which counts the number of rows we have and uses this to generate a new rowId. We use the new rowId to expand the tableData state to include a new defaultRow. I defined defaultRow outside of the function, this prevents it from being redeclared on every render.
import React, { useState } from 'react'
import { Table, Input, Button } from 'reactstrap'
const defautRow = { colA: '', colB: '' }
const IncreasableTable = props => {
const [tableData, setTableData] = useState({
row1: { colA: '', colB: '' }
})
const handleAddRowClick = () => {
const extantRowsCount = Object.keys(tableData).length
setTableData(s => ({
...s,
[`row${extantRowsCount}`]: defautRow
}))
}
return (
<>
<Table>
{
Object.entries(tableData).map(([rowId, data]) => {
const handleChange = ({ target: { name, value } }) => {
setTableData(s => ({
...s,
[rowId]: {
...s[rowId],
[name]: value
}
}))
}
return (
<tr key={rowId}>
<td>
<Input name="colA" value={data.colA} onChange={handleChange}/>
<Input name="colB" value={data.colB} onChange={handleChange}/>
</td>
</tr>
)
})
}
</Table>
<Button onClick={handleAddRowClick}>Click me to add more rows</Button>
</>
)
}
export default IncreasableTable

How to only delete one item at a time in ReactJS?

I'd like to, when a user deletes on row, for only that row to be deleted. Currently that only happens sometimes. And when you have only two items left to delete, when you click on the delete button, the row's data toggles and replaces itself. It doesn't actually delete.
mainCrud.js - houses the add and delete
crudAdd.js - defines state, event handlers, renders the form itself
crudTable.js - maps pre-defined rows defined in mainCrud.js, renders the table itself
Link to CodeSandbox (tables are under campaigns, dev and news tabs).
Any idea what could be causing this?
MainCrud.js
import React, { useState } from "react";
import CrudIntro from "../crud/crudIntro/crudIntro";
import CrudAdd from "../crud/crudAdd/crudAdd";
import CrudTable from "../crud/crudTable/crudTable";
const MainCrud = props => {
// Project Data
const projectData = [
{
id: 1,
name: "Skid Steer Loaders",
description:
"To advertise the skid steer loaders at 0% financing for 60 months.",
date: "February 1, 2022"
},
{
id: 2,
name: "Work Gloves",
description: "To advertise the work gloves at $15.",
date: "February 15, 2022"
},
{
id: 3,
name: "Telehandlers",
description: "To advertise telehandlers at 0% financing for 24 months.",
date: "March 15, 2022"
}
];
const [projects, setProject] = useState(projectData);
// Add Project
const addProject = project => {
project.id = projectData.length + 1;
setProject([...projects, project]);
};
// Delete Project
const deleteProject = id => {
setProject(projectData.filter(project => project.id !== id));
};
return (
<div>
<section id="add">
<CrudIntro title={props.title} subTitle={props.subTitle} />
<CrudAdd addProject={addProject} />
</section>
<section id="main">
<CrudTable projectData={projects} deleteProject={deleteProject} />
</section>
</div>
);
};
export default MainCrud;
CrudAdd.js
import React, { Component } from "react";
import "../crudAdd/crud-add.scss";
import "../../button.scss";
class CrudAdd extends Component {
state = {
id: null,
name: "",
description: "",
date: ""
};
handleInputChange = e => {
let input = e.target;
let name = e.target.name;
let value = input.value;
this.setState({
[name]: value
});
};
handleFormSubmit = e => {
e.preventDefault();
this.props.addProject({
id: this.state.id,
name: this.state.name,
description: this.state.description,
date: this.state.date
});
this.setState({
// Clear values
name: "",
description: "",
date: ""
});
};
render() {
return (
<div>
<form onSubmit={this.handleFormSubmit}>
<input
name="name"
type="name"
placeholder="Name..."
id="name"
value={this.state.name}
onChange={e => this.setState({ name: e.target.value })}
required
/>
<input
name="description"
type="description"
placeholder="Description..."
id="description"
value={this.state.description}
onChange={e => this.setState({ description: e.target.value })}
required
/>
<input
name="date"
type="name"
placeholder="Date..."
id="date"
value={this.state.date}
onChange={e => this.setState({ date: e.target.value })}
required
/>
<button type="submit" className="btn btn-primary">
Add Project
</button>
</form>
</div>
);
}
}
export default CrudAdd;
CrudTable.js
import React, { Component } from "react";
import "../crudTable/crud-table.scss";
class CrudTable extends Component {
render() {
const props = this.props;
return (
<div>
<div class="table-responsive">
<table class="table">
<thead>
<tr>
<th scope="col">Project Name</th>
<th scope="col">Project Description</th>
<th scope="col">Date</th>
<th scope="col"> </th>
</tr>
</thead>
<tbody>
{props.projectData.length > 0 ? (
props.projectData.map(project => (
<tr key={project.id}>
<td>{project.name}</td>
<td>{project.description}</td>
<td>{project.date}</td>
<td>
<button className="btn btn-warning">Edit</button>
<button
onClick={() => props.deleteProject(project.id)}
className="btn btn-danger"
>
Delete
</button>
</td>
</tr>
))
) : (
<tr>
<td>No projects found. Please add a project.</td>
</tr>
)}
</tbody>
</table>
</div>
</div>
);
}
}
export default CrudTable;
This is because you are filtering over projectData. Update your deleteProject method to filter over your React.useState projects variable and it will work.
const deleteProject = id => {
setProject(projects.filter(project => project.id !== id));
};
See code sandbox example here.

Select all checkbox of table on click of the another table checkbox using react

I have checkboxes for each td in a table. Now, I have another table which has one checkbox. On checking this, I want to select all other checkboxes of first table.
Here is the code,
<tr key={key}>
<td align="center"> <input type="checkbox" name="myTextEditBox" value="checked" /></td>
<td>{item.technology}</td>
</tr>
for second table I did,
handleCheckBox = () => {
console.log("callling the handle change");
this.setState({
isCheckd: !this.state.isCheckd
})
}
constructure(props) {
this.state = { isCheckd: false }
<td className="text-right mr-1"><input type="checkbox" checked={this.state.isCheckd} onChange={this.handleCheckBox} /></td>
}
Now, In this click handler works. But, now how do I select all other checkboxes of another table, without using jquery.
Can any one help me with this ?
Tried solution -
state = { dynamicProp: {}, isCheckd: false,}
handleCheckBox = () => {
this.setState({
isCheckd: !this.state.isCheckd
}, () => {
this.props.jobs.forEach((item) =>
this.setState(prevState => ({
dynamicProp: {
...prevState.dynamicProp,
[item.jdName]: prevState.isCheckd
}
})
))
});
}
handleTableCheckboxChange = (e) => {
const target = e.target.name;
const checked = e.target.checked;
this.setState(prevState => ({
dynamicProp: {
...prevState.dynamicProp,
[target]: checked
}
}), () => {
const result = this.allTrue(this.state.dynamicProp);
this.setState({
isCheckd: result ? false : true
})
})
}
allTrue(obj) {
for (var o in obj)
if (!obj[o]) return true;
return false;
}
and then passing all the props to the child element. Now, the problem I am facing now is in the handleTableCheckboxChange method where I am not getting the way you used filter to get the unchecked element. and then the select all check will get changed.
I did not understand your code well so I understand it from what you have written. And then I have created a working example for you. Hope it can help you!
UPDATED CODE
const Table=(props)=>(
<table>
{
props.items.map((item, i) => (
<tr key={i}>
<td>
<input type="checkbox" checked={props.parentState[item.name]} name={item.name} onChange={props.handleChange} />
</td>
<td>{item.value}</td>
</tr>
))
}
</table>
);
class App extends React.Component {
items = [
{
value: 'EN',
name: 'field1'
},
{
value: 'IT',
name: 'field2',
}
];
state = {
checkAll: false,
};
render() {
return (
<div>
Check All
<input type="checkbox" onChange={this.handleCheckAll} checked={this.state.checkAll}/>
<Table
handleChange={this.handleChange}
items={this.items}
parentState={this.state}
/>
</div>
);
}
handleCheckAll = () => {
this.setState({
checkAll: !this.state.checkAll
}, () => {
this.items.forEach((item) => this.setState({ [item.name]: this.state.checkAll}))
});
}
handleChange = (e) => {
this.setState({
[e.target.name]: e.target.checked
}, () => {
const uncheckedItems = this.items.filter((item) => !this.state[item.name])
this.setState({
checkAll: uncheckedItems.length === 0?true:false
});
});
}
}
ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>
Here's a sample code. Obviously i haven't covered all the fail cases. Still you will get an idea about how that can be done.
import React from 'react';
export default class CheckboxIndex extends React.Component{
constructor(props){
super(props);
this.state = {
isChecked : false,
allTDS : [
{name:"name 1",value:false},
{name:"name 2",value:false},
{name:"name 3",value:false},
{name:"name 4",value:false},
{name:"name 5",value:false},
{name:"name 6",value:false},
{name:"name 7",value:false}
]
}
}
handleCheckBox = () => {
this.setState({isChecked: !this.state.isChecked});
let tempTDS = this.state.allTDS;
for (let i =0; i < tempTDS.length; i++){
tempTDS[i].value = !this.state.isChecked;
}
this.setState({allTDS : tempTDS});
};
render(){
let listOfTR;
if(this.state.allTDS.length){
listOfTR = this.state.allTDS.map((item,index)=>{
return(
<tr key={item.name}>
<td>
<label htmlFor={item.name}>
<input id={item.name} checked={item.value} type="checkbox"
onChange={()=>{
let tempObj = this.state.allTDS;
tempObj[index].value = !tempObj[index].value;
this.setState({allTDS:tempObj});
}}/>{item.name}
</label>
</td>
</tr>
)
})
}
return(
<div>
<label htmlFor="allTDS">
<input type="checkbox" id="allTDS" name="all" checked={this.state.isChecked}
onChange={this.handleCheckBox}/> All
</label>
<table>
<tbody>
{listOfTR}
</tbody>
</table>
</div>
)
}
}
class CheckboxTest extends React.Component {
constructor() {
super();
this.state = {
selectAll: false,
data1: false,
data2: false
};
this.selectAll = this.selectAll.bind(this);
this.selectField = this.selectField.bind(this);
}
selectAll() {
this.setState({
data1: !this.state.selectAll,
data2: !this.state.selectAll,
selectAll: !this.state.selectAll
});
}
selectField(event) {
if (event.target.value === "data1")
this.setState({ data1: !this.state.data1 });
else this.setState({ data2: !this.state.data2 });
}
render() {
return (
<div className="App">
<table>
<tbody>
<tr>
<td align="center">
<input
checked={this.state.data1}
onChange={this.selectField}
type="checkbox"
name="myTextEditBox1"
value="data1"
/>
</td>
<td>data 1</td>
</tr>
<tr>
<td align="center">
<input
checked={this.state.data2}
onChange={this.selectField}
type="checkbox"
name="myTextEditBox2"
value="data2"
/>
</td>
<td>data 2</td>
</tr>
</tbody>
</table>
<table>
<tbody>
<tr>
<td align="center">
<input
onChange={this.selectAll}
type="checkbox"
name="myTextEditBox1"
value="all"
/>
</td>
<td>Click all</td>
</tr>
</tbody>
</table>
</div>
);
}
}
You can use the state for implementing this. Maintain state for each checkbox field and when the checkbox is changed trigger a method to set the state according to your conditions
this.setState({
isCheckd: !this.state.isCheckd
})
In this case, the isCheckd value in state corresponds to one checkbox. To select all other checkboxes of another table you have to update the values set in setState to all the values that correspond to all the boxes you want checked.
So if you have another 3 checkboxes who's values correspond to isCheckd1, isCheckd2, and isCheckd3 in state then your handler would be:
this.setState({
isCheckd1: true,
isCheckd2: true,
isCheckd3: true
})
Try this approach. you can select both the individual and check all checkbox.
class App extends React.Component {
items = ['EN', 'IT', 'FR', 'GR', 'RU'];
state = {
checkAll: false,
items : [
{'label': 'EN', 'checked': false},
{'label': 'IN', 'checked': false},
{'label': 'FR', 'checked': false},
]
};
render() {
return (
<div>
Check All
<input type="checkbox" onChange={this.handleCheckAll} />
<table>
{
this.state.items.map((item, i) => (
<tr key={i}>
<td>
<input type="checkbox" checked={item.checked} />
</td>
<td>{item.label}</td>
</tr>
))
}
</table>
</div>
);
}
handleCheckAll = () => {
let checkAll = !this.state.checkAll;
let items = this.state.items;
items.map((item, i) => {
item.checked = checkAll;
});
this.setState({
checkAll,
items
});
}
}

React : How to manage state for multiple input types

Working on a POC that displays tennis player details in a page.There can be 'n' number of players displayed. The user can update information of all the players at the same time.
Written 3 components PlayersPage, PlayerTable and PlayerRow. I am little confused on how to update the state(playerData) in PlayersPage when the player information is updated in PlayerRow. Any pointer/link will be helpful.
Below is the code:
class PlayersPage extends React.Component {
constructor(props) {
super(props);
this.state = {
playerData: [
{
"dataKey": "300",
"playerFirstName": "Roger",
"playerLastName": "Federer",
"playerRanking": "1"
},
{
"dataKey": "301",
"playerFirstName": "Rafael",
"playerLastName": "Nadal"
"playerRanking": "2"
}
]
};
}
render() {
return (
<div className="container">
<PlayerTable tableData={this.state.playerData} />;
</div>
);
}
}
class PlayerTable extends React.Component {
render() {
const rows = [];
this.props.tableData.forEach((rowData) => {
rows.push(<PlayerRow key={rowData.dataKey} rowData={rowData} />);
});
return (
<div className="table-responsive">
<table className="table table-condensed">
<thead>
<tr>
<th>First Name</th>
<th>Last Name</th>
<th>Ranking</th>
</tr>
</thead>
<tbody>
{rows}
</tbody>
</table>
</div>
);
}
}
PlayerTable.propTypes = {
tableData: PropTypes.array.isRequired
};
class PlayerRow extends React.Component {
render() {
return (
<tr>
<td><input type="text" value={this.props.rowData.playerFirstName} /></td>
<td><input type="text" value={this.props.rowData.playerLastName} /></td>
<td><input type="text" value={this.props.rowData.playerRanking} /></td>
</tr>
);
}
}
PlayerRow.propTypes = {
rowData: PropTypes.object.isRequired
};
class PlayersPage extends React.Component {
constructor(props) {
super(props);
this.changeRecord = this.changeRecord.bind(this);
this.state = {
playerData: [
{
"dataKey": "300",
"playerFirstName": "Roger",
"playerLastName": "Federer",
"playerRanking": "1"
},
{
"dataKey": "301",
"playerFirstName": "Rafael",
"playerLastName": "Nadal",
"playerRanking": "2"
}
]
};
}
changeRecord(record, event) {
console.log(event.currentTarget.value);
console.log(record);
this.setState({
// Write your logic to update the playerDate value accordingly
});
}
render() {
return (
<div className="container">
<PlayerTable recordChangeHandler={this.changeRecord} tableData={this.state.playerData} />;
</div>
);
}
}
class PlayerTable extends React.Component {
render() {
const rows = [];
this.props.tableData.forEach((rowData) => {
rows.push(<PlayerRow recordChangeHandler={this.props.recordChangeHandler} key={rowData.dataKey} rowData={rowData} />);
});
return (
<div className="table-responsive">
<table className="table table-condensed">
<thead>
<tr>
<th>First Name</th>
<th>Last Name</th>
<th>Ranking</th>
</tr>
</thead>
<tbody>
{rows}
</tbody>
</table>
</div>
);
}
}
class PlayerRow extends React.Component {
render() {
return (
<tr>
<td><input type="text" onChange={this.props.recordChangeHandler.bind(this, this.props.rowData)} defaultValue={this.props.rowData.playerFirstName} /></td>
<td><input type="text" onChange={this.props.recordChangeHandler} defaultValue={this.props.rowData.playerLastName} /></td>
<td><input type="text" onChange={this.props.recordChangeHandler} defaultValue={this.props.rowData.playerRanking} /></td>
</tr>
);
}
}
ReactDOM.render(
<PlayersPage />,
document.getElementById('container')
);
Checkout the JSFiddle example you can probably emulate in your POC app.
https://jsfiddle.net/69z2wepo/86736/
Component communication can be achieved by passing data via props.
Check out this link, specifically section 3.
How do you send data from a child to its parent?
The simplest way is for the parent to pass a function to the child. The child can use that function to communicate with its parent.
The parent would pass a function to the child as a prop, like this:
<MyChild myFunc={this.handleChildFunc.bind(this)} />
And the child would call that function like so:
this.props.myFunc();
And don't forget that the child will need this function declared in its propTypes:
MyChild.propTypes = {
myFunc: React.PropTypes.func,
};

Categories