how to add row to a table using ReactJS on button click - reactjs

I have a table and I want to add a row to it when ADD button is clicked. How can I do that using ReactJS instead of simple JavaScript?
code:
var RecordsComponent = React.createClass({
render : function() {
return (
<div>
<table>
<tr>
<td>row 1</td>
</tr>
<tr>
<td>row 2</td>
</tr>
<tr>
<td}>row 3</td>
</tr>
</table>
<button id="addBtn" onClick={addRow}>ADD</button>
</div>
);
},
addRow : function() {
//how to add row using ReactJS?
},
});
React.render(<RecordsComponent/>, document.getElementById('display'))

You need to make your React component have a state and render the component accordingly based on that data. Forget the old "DOM modification" paradigm where you are playing directly with HTML elements.
Untested but should carry the idea across:
var RecordsComponent = React.createClass({
getInitialState: {
return {
rows: ['row 1', 'row 2', 'row 3']
}
},
render : function() {
return (
<div>
<table>
{rows.map((r) => (
<tr>
<td>{r}</td>
</tr>
))}
</table>
<button id="addBtn" onClick={addRow}>ADD</button>
</div>
);
},
addRow : function() {
var rows = this.state.rows
rows.push('new row')
this.setState({rows: rows})
},
});
React.render(<RecordsComponent/>, document.getElementById('display'))
If you're just starting to learn React with your own test apps I would recommend using the most recent version of React, along with, among a lot of other things, the React ES6 class definitions.

Try something like this
var RecordsComponent = React.createClass({
getInitialState: function () {
return {
tablerows:[
{fname:"Tom",lname:"Moody",age:23}
]
};
},
addRow: function() {
// add new data from here
var newdata = {fname:"Tom",lname:"Moody",age:23}
//take the existing state and concat the new data and set the state again
this.setState({ tablerows: this.state.tablerows.concat(newdata ) });
},
rows:function(){
return this.state.tablerows.map(function(row,i){
return (<tr key={i}>
<td>{row.fname}</td>
<td>{row.lname}</td>
<td>{row.age}</td>
</tr>);
});
},
render : function() {
return (
<div>
<table>
<tr>
<td> row 1 </td>
</tr>
<tr>
<td> row 2 </td>
</tr>
<tr>
<td> row 3 </td>
</tr>
{this.rows()}
</table>
<button id= "addBtn" onClick={this.addRow}>ADD</button>
</div>
);
}
});
React.render(<RecordsComponent/>, document.getElementById('display'))

Related

react mapping function not working

hey all i have this array of objects
this.state = {
users :[{
userid:'1',
fullName :'eddyabikhalil',
dob:'10/03/1994',
gender:'M',
loan:[{
loanid:'1',
date:'20/7/2012',
loanValue:'100$',
},
{
loanid:'2',
date:'21/4/2014',
loanValue:'200$',
},
{
loanid:'3',
date:'20/12/2015',
loanValue:'300$',
}]
},
userid:'2',
fullName :'joe salloum',
dob:'11/04/1993',
gender:'M',
loan:[{
loanid:'4',
date:'20/7/2012',
loanValue:'500$',
},
{
loanid:'5',
date:'21/4/2017',
loanValue:'600$',
},
{
loanid:'6',
date:'20/12/2012',
loanValue:'700$',
}
],
}]
}
}
so i wrote this function to map inside of this array of object:
renderTable(userValue) {
let HTML = [];
let groupedVals = groupBy(userValue, 'userid');
let usersObj = [];
map(groupedVals, (value, key) => {
let userss = {
FullName: value.fullName,
dob: value.dob,
gender: value.gender,
loans: []
}
map(value, (subValue) => {
userss.loans.push(subValue.loanValue)
})
usersObj.push(userss);
})
map(usersObj, (val) => {
HTML.push(<tr>
<td>
{val.FullName}
</td>
<td>
{val.dob}
</td>
<td>
{val.gender}
</td>
<td>
{val.loans.join(',')}
</td>
</tr>
)
})
return HTML;
}
i want to make a table with the following fields: fullName, dob, gender and loan
i want to show that userid = 1 have multiple loan value in one td
so i created this table:
render() {
return (
<div className="container">
<table className="table table-striped">
<thead>
<tr>
<td>FullName</td>
<td>dob</td>
<td>gender</td>
<td>loans</td>
</tr>
</thead>
<tbody>
{
this.state.users &&
this.renderTable(this.state.users)
}
</tbody>
</table>
</div>
);
}
any help guys? thanks in advance
render() {
return (
<div className="container">
<table className="table table-striped">
<thead>
<tr>
<td>FullName</td>
<td>dob</td>
<td>gender</td>
<td>loans</td>
</tr>
</thead>
<tbody>
{
this.state.users.map((user) => (
<tr>
<td>{user.fullName}</td>
<td>{user.dob}</td>
<td>{user.gender}</td>
<td>{user.loan.map((loan) => { return (loan.id + ",") })}</td>
</tr>
))
}
</tbody>
</table>
</div>
);
}

How to delete an entire row from html table using ReactJS?

I want to delete an entire row (text & button) from html table on button click. How can I do that using ReactJS instead of using simple JavaScript?
code:
var RecordsComponent = React.createClass({
render : function() {
return (
<div>
<table>
<tr>
<td>row 1</td>
<td><button onClick={deleteRow}>DELETE</button></td>
</tr>
<tr>
<td>row 2</td>
<td><button onClick={deleteRow}>DELETE</button></td>
</tr>
<tr>
<td}>row 3</td>
<td><button onClick={deleteRow}>DELETE</button></td>
</tr>
</table>
</div>
);
},
deleteRow : function() {
//how to delete row using ReactJS?
},
});
React.render(<RecordsComponent/>, document.getElementById('display'))
You should to know how to make a react components.
Below is one of example to delete items.
class RecordsComponent extends React.Component {
constructor() {
super();
this.state = {
rows: ['row 1', 'row 2', 'row 3'],
};
}
deleteRow = (index) => {
// make new rows. note: react state is immutable.
const newRows = this.state.rows.slice(0, index).concat(this.state.rows.slice(index + 1));
this.setState({
rows: newRows,
});
};
render() {
const rows = this.state.rows.map((row, index) => (
<tr key={row}>
<td>{row}</td>
<td><button onClick={() => { this.deleteRow(index); }}>DELETE</button></td>
</tr>
));
return (
<div>
<table>
{rows}
</table>
</div>
);
}
}

Render table when getting data asynchronous

I have some data which i get in state when componentDidMount.
I am trying render table using this data.
In my case rows not rendering.
How i can send data to tbody ?
export default class App extends Component {
constructor(props) {
super(props);
this.state={rows:null}
}
componentDidMount(){
var rows=[]
Meteor.http.call("GET", url ,function(error,result){
$.each(JSON.parse(result.content), function(key, value){
rows.push(value)
});
this.setState({
rows:rows});
})
}
renderRows(){
$.each(this.state.rows, function(d){
return(
<tr>
<td>{d[0]}</td>
<td>{d[1]}</td>
<td>{d[2]}</td>
<td>{d[3]}</td>
</tr>
)
})
}
render(){
return(
<Table>
<thead>
<tr>
<th>col1</th>
<th>col2</th>
<th>col3</th>
<th>col4</th>
</tr>
</thead>
<tbody>
{this.renderRows}
</tbody>
</Table>
)
}
}
Another option, not using JQuery and avoiding having a separate render function, is to use .map
React likes it if you have a unique key on each element in a list, so hopefully one of the fields on your row can serve this purpose.
render(){
return(
<Table>
<thead>
<tr>
<th>col1</th>
<th>col2</th>
<th>col3</th>
<th>col4</th>
</tr>
</thead>
<tbody>
{this.state.rows.map(d => (
<tr key={d[0]}>
<td>{d[0]}</td>
<td>{d[1]}</td>
<td>{d[2]}</td>
<td>{d[3]}</td>
</tr>
)}
</tbody>
</Table>
)
}
You'll also need to set your initial state for rows to be [] rather than null, in order for the first render to work.
renderRows is a function so you need to execute it. Also you will need to update that function a bit:
export default class App extends Component {
// ...
componentDidMount(){
var rows=[];
var self = this;
Meteor.http.call("GET", url ,function(error,result){
$.each(JSON.parse(result.content), function(key, value){
rows.push(value)
});
self.setState({
rows: rows
});
});
}
renderRows(){
const rows = this.state.rows || [];
return rows.map(d => {
return(
<tr>
<td>{d[0]}</td>
<td>{d[1]}</td>
<td>{d[2]}</td>
<td>{d[3]}</td>
</tr>
);
});
}
render(){
return(
<Table>
{/* ... */}
<tbody>
{this.renderRows()}
</tbody>
</Table>
)
}
}

Binding data grid to form

I have a simple table of data on the left side of my UI and a form on the right. As a brand new user to ReactJS I was able to accomplish this without much difficulty. However, I would like the user to be able to click the Name column from each row and have it populate the form on the right. I have a similar page using jQuery and a small routing library where I simply link each row to a route like #edit/:id and use jQuery to manually bind via the selectors. The reason I am trying out React is to avoid having to do this.
Anywhere here is my code so far. Just a main App component with the form and table in separate components.
var TplList = React.createClass({
getInitialState() {
return {
data: { rows: [] }
};
},
componentDidMount() {
$.ajax({
type: "GET",
dataType: "json",
url: this.props.url,
success: function(response) {
//console.log(response);
this.setState({
data: response
});
}.bind(this),
error: function(xhr, status, err) {
console.error(this.props.url, status, err.toString());
}.bind(this)
});
},
render: function() {
var tblRows = this.state.data.rows.map(function(result, index) {
return <TplRow key={index} tpl={result} />
});
return (
<div>
<h3 className="formHeader">Workcell - Master Templates</h3>
<table id="tplDataTable" width="100%" className="form" cellpadding="2" cellspacing="0" border="0">
<thead>
<tr className="titleGreen">
<th>Name</th>
<th>By</th>
<th>Date</th>
<th className="th_right">R/C</th>
<th className="th_right">Copies</th>
<th className="th_right">Vol (10mM)</th>
</tr>
</thead>
<tbody>{tblRows}</tbody>
</table>
</div>
);
}
});
var TplRow = React.createClass({
handleNameClick: function() {
},
render: function() {
var tpl = this.props.tpl;
var cls = (tpl.index % 2 > 0) ? "" : "alt";
var volume = (tpl.volume > 0) ? tpl.volume + "\u00b5" + "l" : "\u00a0";
return (
<tr className={cls}>
<td><a href="#" onClick={handleNameClick}>{tpl.name}</a></td>
<td>{tpl.username}</td>
<td>{tpl.cre_date}</td>
<td>{tpl.compound_placement}</td>
<td>{tpl.copies}</td>
<td>{volume}</td>
</tr>
);
}
});
var TplForm = React.createClass({
getInitialState() {
return {
"copies": 10
};
},
render: function() {
return (
<div>
<h3 className="formHeader">Edit Master Template</h3>
<table className="form" width="100%" cellpadding="3" cellspacing="0">
<tbody>
<tr>
<td className="label"><label htmlFor="tplCopies">Copies</label></td>
<td className="field">
<input
type="number" min="0" max="500"
name="tplCopies"
id="tplCopies"
value={this.state.copies} />
</td>
</tr>
</tbody>
</table>
</div>
);
}
});
var MasterTemplateApp = React.createClass({
render: function() {
return (
<div id="container">
<div id="wc_tpl_left">
<TplList url="/cfc/com_admin_transfer.cfc?method=getWCTemplateData" />
</div>
<div id="wc_tpl_right">
<TplForm />
</div>
<div className="tpl_clear"></div>
</div>
);
}
});
ReactDOM.render(<MasterTemplateApp />, document.getElementById('app_wc_master_tpl'));
you should write your handleNameClick method like this
handleNameClick: function() {
ReactDOM.render(<TplForm />, document.getElementById('wc_tpl_right'))
}
don't forget to remove TplForm from
<div id="wc_tpl_right">
<TplForm />
</div>
hope this helps

How to get a onClick to work in a row - reactjs

I am trying to get a click even to work with a table in reactjs. My first attempt was to make the whole row clickable. Here is my code:
var UserList = React.createClass({
getInitialState: function() {
return getUsers();
},
handleClick: function(e) {
console.log("clicked");
},
render: function() {
var users = this.state.users.map(function(user) {
return (
<tr onClick={this.handleClick}>
<td>{user.name}</td>
<td>{user.age}</td>
<td></td>
</tr>
);
});
return(
<div className="container">
<table className="table table-striped">
<thead>
<tr>
<th>Name</th>
<th>Age</th>
<th>Full Detail</th>
</tr>
</thead>
<tbody>
{users}
</tbody>
</table>
</div>
);
}
});
This did not work. I then tried to add a button in the table:
<button className="btn" onClick={this.handleClick}>Full Detail</button>
That also did not work. I have other onClick's working throughout my app, but how do I make this work with a table?
Your problem is the function of user that creates the table row is not bound to your react component. The value of this will not be your react component and handleClick will not exist as a property of this.
Try
var users = this.state.users.map(function(user) {
return (
<tr onClick={this.handleClick}>
<td>{user.name}</td>
<td>{user.age}</td>
<td></td>
</tr>
);}.bind(this);
});
Or use Underscore's bind if you want it to work on all browsers.
I'm new to react. How about this? You just wrap it in another function, then that function holds the closure scope and it calls it correctly.
No idea if this is bad practice or the performance difference, but it seems to work...
var users = this.state.users.map(function(user) {
return (
<tr onClick={()=>this.handleClick(user)}>
<td>{user.name}</td>
<td>{user.age}</td>
<td></td>
</tr>
);}.bind(this);
});
Binding creates a new object. Thus if you bind your function for N employees, you are inefficiently creating N new functions. A more elegant approach is to bind the function once, and pass a reference to every row. Your original code was quite close. This is what I would suggest:
handleClick = e => {
const user = this.state.users.find(u => u.uuid == e.target.dataset.uui)
console.log("clicked");
},
render() {
return(
<div className="container">
<table className="table table-striped">
<thead>
<tr>
<th>Name</th>
<th>Age</th>
<th>Full Detail</th>
</tr>
</thead>
<tbody>
{this.state.users.map(user =>
(
<tr data-uuid={user.uuid} onClick={this.handleClick}>
<td>{user.name}</td>
<td>{user.age}</td>
<td>{user.details || ''}</td>
</tr>
)
)}
</tbody>
</table>
</div>
);
}
});

Resources