I'm new to React and have created a dynamic tablefrom a JSON received from the back-end server that I have. For each table row I have a button that opens to a dropdown which has two options - to edit the information in the row and to delete the row. I've made a separate component for the dropdown button and presently am passing the ID of the row to it.
With the present code, I'm able to delete the row but can only see the change on refreshing the page. I've looked at other answers to problems like mine with people saying the state needs to be updated but I'm confused about how to go about it in this case.
EDIT: I'm not use anything for managing state. Just plain simple React
This is the code for the table that gets rendered :-
<table className="table">
<thead>
<tr>
<th>S. NO.</th>
<th>NAME</th>
<th>AGE</th>
<th>ADDRESS</th>
<th></th>
</tr>
</thead>
<tbody>
{this.state.personData.map((Row, idx) => (
<tr key={Row.id}>
<td>{idx + 1}</td>
<td>{Row.name}</td>
<td>{Row.age}</td>
<td>{Row.addr}</td>
<td>
{" "}
<DropDownButton id={Row.id} />{" "}
</td>
</tr>
))}
</tbody>
</table>
This is the code in the DropDownButton component :-
handleDelete() {
console.log("ID " + this.props.id);
fetch("http://localhost/person/" + this.props.id, {
method: "DELETE",
headers: {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Headers": "Content-Type"
}
})
.catch(error => console.log("Error:", error))
.then(response => console.log("Success:", response));
}
render() {
return (
<React.Fragment>
<div className="dropdown">
<button
type="button"
className="btn dropdown-toggle dropdownButton"
data-toggle="dropdown"
>
OPTIONS
</button>
<div className="dropdown-menu">
<p className="dropdown-item" onClick={this.handleEdit}>
EDIT
</p>
<p className="dropdown-item" onClick={this.handleDelete}>
DELETE
</p>
</div>
</div>
</React.Fragment>
);
}
}
In your parent component you need to make a callback method that will remove the data from this.state.personData like the method I wrote below
onDelete = (id) => {
this.setState({
...this.state,
personData: this.state.personData.filter((row) => row.id !== id)
});
}
render = () => {
return (
<table className="table">
<thead>
<tr>
<th>S. NO.</th>
<th>NAME</th>
<th>AGE</th>
<th>ADDRESS</th>
<th></th>
</tr>
</thead>
<tbody>
{this.state.personData.map((Row, idx) => (
<tr key={Row.id}>
<td>{idx + 1}</td>
<td>{Row.name}</td>
<td>{Row.age}</td>
<td>{Row.addr}</td>
<td>
{" "}
<DropDownButton id={Row.id} onDelete={this.onDelete} />{" "}
</td>
</tr>
))}
</tbody>
</table>
);
};
And then in your DropDownButton you need to call this onDelete callback
handleDelete () {
console.log("ID " + this.props.id);
fetch("http://localhost/person/" + this.props.id, {
method: "DELETE",
headers: {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Headers": "Content-Type"
}
})
.catch(error => console.log("Error:", error))
.then(response => {
// call the passed in onDelete method here with the cooresponding id
this.props.onDelete(this.props.id);
console.log("Success:", response)
});
}
render () {
// ...
}
when this onDelete callback is called, the state in the parent component will change, causing it to rerender the list with only the items in the new list
I have a problem that may be related to what is discussed in this thread.
After adding or editing a column I am changing the color of the cells, but when I delete a row even though the state has changed the the cell colors remain intact until I change the pagination.
Edited
Following stackOverflow's behavioral steps, create a separate thread to address the problem.
In case someone has the same problem you can see the solution to the problem in this thread.
Related
Let me explain the issue, I am trying to show some details in a modal. I am using table in the modal to show details. In one section, I need the product name which is returned from a database query and I have to use that value returned from the database. The code for table is as follows:
<tbody>
{item.cartItems.map((item, i) =>
<tr key={item._id}>
<th scope="row">{i + 1}</th>
<th><img src={`${API}/product/photo/${item.product}`} alt={item.product.name} width="60px" height="50px" /></th>
<td>{**data returned from database**}</td>
<td align="center">{item.count}</td>
<td align="center">৳ {item.price * item.count} </td>
</tr>
)}
</tbody>
To get the data from the database, I am using a function
const getProdcutName = id => {
var productName;
getProductDetails(id)
.then(response => {
productName = response.data.name;
});
return productName;
}
But I can't access the value. The main thing is, in every Iteration I need to send the {item.product} to getProductName(id) and I need the name from the database in return. But I can't access the data from promise scope to return it.
This is the solution to my issue. Thanks to everyone who helped me out.
const CartItem = ({ item, i }) => {
const [productName, setProductName] = useState();
useEffect(() => {
getProductDetails(item.product)
.then(res => { setProductName(res.data.name) });
}, []);
return (
<tr key={item._id}>
<th scope="row">{i + 1}</th>
<th><img src={`${API}/product/photo/${item.product}`} alt={item.product.name} width="60px" height="50px" /></th>
<td>{productName == undefined ? "Getting Name" : productName}</td>
<td align="center">{item.count}</td>
<td align="center">৳ {item.price * item.count} </td>
</tr>
)}
And to send items to the cartItem
<tbody>
{item.cartItems.map((item, i) =>
<CartItem item={item} i={i} key={item._id} />
)}
</tbody>
I am facing a weird problem while working with tankStack react-table. I want render some specific tags with extra data. example: i want to render the age column like this (this is the {age})
But don't want to make the tag child of tag but that is happening
Here is my code
<table>
<thead>
{table.getHeaderGroups().map((headerGroup) => (
<tr key={headerGroup.id}>
{headerGroup.headers.map((header) => (
<th key={header.id}>
{header.isPlaceholder
? null
: flexRender(
header.column.columnDef.header,
header.getContext()
)}
</th>
))}
</tr>
))}
</thead>
<tbody>
{table.getRowModel().rows.map((row) => (
<tr key={row.id}>
{row.getVisibleCells().map((cell) => {
return(
<td key={cell.id}>
{flexRender(
cell.column.columnDef.cell,
cell.getContext()
)}
</td>
)
})
}
</tr>
))}
</tbody>
</table>
Column.js
export const COLUMNS = [
{
header:'First Name',
accessorKey:'first_name',
id:'first_name'
},
{
header:'Last Name',
accessorKey:'last_name',
id:'last_name'
},
{
header:'Age',
accessorKey:'age',
id:'age',
cell: data => <td>this is age{data.getValue()}</td>,
enableGlobalFilter: false,
}
]
I can't find where the issue is in my code,my delete function is deleting everything in the state but is not deleting a customer in the database.Can someone tell me where the issue is? I checked on my HTTP route and it seems fine. I also tried removing all the conditions to see if it works but it deletes all the records in the view but not in the database.Am I missing something?Thanks.
This is my delete function code:
deleteCustomer(id){
let confirmDeletion = window.confirm('Do you really wish to delete it?');
if (confirmDeletion) {
fetch('api/Customer/Delete/' + id, {
method:'delete'
})
.then(data => {
this.setState(
{
cusList: this.state.cusList.filter((rec) => {
return (rec.customerId != id);
})
});
});
}
}
This is my render where all the data is deleted when a delete button of one customer is clicked
and then displays"No customers yet":
renderCustomerTable = (cusList) => {
return (
<table className="ui celled fixed single line table">
<thead className="">
<tr className="">
<th className="">Name</th>
<th className="">Address</th>
<th className="">Action</th>
<th className="">Action</th>
</tr>
</thead>
<tbody className="">
{!cusList || cusList.length <=0 ?
<tr><td colSpan="6" align="center"><b>No Customers yet</b></td></tr>
:this.state.cusList.map(cus =>
<tr className="" key={cus.customerId}>
<td className="">{cus.name}</td>
<td className="">{cus.address}</td>
<td className="">
<Button className="ui yellow icon left labeled button " ><i aria-
hidden="true" class="edit icon"></i>Edit</Button>
</td>
<td className="">
<Button className="ui red icon left labeled button " onClick={(id) =>
this.deleteCustomer(cus.customerId)}><i aria-hidden="true" class="delete icon">
</i>Delete</Button>
</td>
</tr>
)}
</tbody>
</table>);
}
This is my controller:
[HttpGet]
[Route("api/Customer/Details/{id}")]
public Customer Details(int id)
{
return objcustomer.GetCustomerData(id);
}
This is my customerdataaccess:
public int DeleteCustomer(int id)
{
try
{
Customer cus = db.Customer.Find(id);
db.Customer.Remove(cus);
db.SaveChanges();
return 1;
}
catch
{
throw;
}
}
```
Try this.
fetch(`/api/Customer/Delete/${id}`, {
method:'delete'
})
.then(data => {
this.setState(prevState=>({
cusList: prevState.cusList.filter((rec)=>rec.customerId != id)
});
});
Why in the following code Delete button click does not hit the delete method? What i am missing important thing? I am new to learn React.js
delete(e) {
console.log('Deleted');
}
static renderCatTable(Categories) {
return (
<table className='table table-striped'>
<thead>
<tr>
<th>Code</th>
<th></th>
</tr>
</thead>
<tbody>
{Categories.map(category =>
<tr key={category._id}>
<td>{category.code}</td>
<td><button onClick={this.delete} className="btn btn-danger">Delete</button></td>
</tr>
)}
</tbody>
</table>
);
}
I have defined the binding inside the constructor
this.delete = this.delete.bind(this);
The render function is given below.
render() {
let contents = this.state.loading
? <p><em>Loading...</em></p>
: Category.renderCatTable(this.state.Categories);
return (
<div>
{contents}
</div>
);
}
Because that render method is static. By definition, static methods cannot access an instance variable. You should remove that modifier if possible and it should work.
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>
);
}
});