I have a table that the user can edit the rows so i can save it into a state and save it inside a database but how can i get table row values and save it inside a state ? therefor the rows can be dynamic rows for example like grade i will fetch how many subjects inside a specific subject and the admin can put numbers inside rows so i can calculate how many grade does the user get for this subject
<table className="table-fill">
<thead>
<tr>
<th className="text-left">Subjects</th>
<th className="text-left">Grade</th>
</tr>
</thead>
<tbody className="table-hover">
<tr>
<td className="text-left" contentEditable="true">subject 1</td>
<td className="text-left" contentEditable="true">50</td>
</tr>
<tr>
<td className="text-left" contentEditable="true">subject 2</td>
<td className="text-left" contentEditable="true">40</td>
</tr>
<tr>
<td className="text-left" contentEditable="true">subject 3</td>
<td className="text-left" contentEditable="true">30</td>
</tr>
</tbody>
</table>
You should not use contentEditable="true" because it have no onChange event, so use input instead
import { useState } from "react";
export default function App() {
const [data, setData] = useState([
{ subject: "subject 1", grade: 50 },
{ subject: "subject 2", grade: 40 },
{ subject: "subject 3", grade: 30 }
]);
const onChangeRow = ({ type, index, value }) => {
const newData = data.map((item, idx) => {
if (idx === index)
return {
...item,
[type]: value
};
return item;
});
setData(newData);
};
const totalGrade = data.reduce((acc, cur) => {
acc += cur.grade;
return acc;
}, 0);
return (
<div className="App">
<table className="table-fill">
<thead>
<tr>
<th className="text-left">Subjects</th>
<th className="text-left">Grade</th>
</tr>
</thead>
<tbody className="table-hover">
{data.map((item, index) => (
<tr key={index}>
<td className="text-left">
<input
type="text"
defaultValue={item.subject}
onChange={(e) =>
onChangeRow({
type: "subject",
index,
value: e.target.value
})
}
/>
</td>
<td className="text-left">
<input
type="number"
defaultValue={item.grade}
onChange={(e) =>
onChangeRow({
type: "grade",
index,
value: parseInt(e.target.value || 0)
})
}
/>
</td>
</tr>
))}
</tbody>
</table>
<div>Total grade: {totalGrade}</div>
</div>
);
}
style.css
input {
border: none;
outline: none;
}
You can check in my codesandbox. Hope it help!
Related
My Delete API is http://localhost:8080/api/inventory/deleteproduct with the request body in JSON format:
{
"upc": "100101101111"
}
upc is the unique value for each product.
Here is my code for fetching data from API:
export function Inventory() {
const [product, setProduct] = useState(null);
useEffect(() => {
axios
.get("http://localhost:8080/api/inventory/products")
.then((response) => {
setProduct(response.data);
});
}, [url]);
if (product) {
return (
<div>
<h1>Inventory</h1>
<table className="table">
<thead>
<tr>
<th scope="col">Product Name</th>
<th scope="col">Brand</th>
<th scope="col">Category</th>
<th scope="col">Product Description</th>
<th scope="col">Price Per Unit</th>
<th scope="col">Available Stock</th>
<th scope="col">Reserved Stock</th>
<th scope="col">Shipped Stock</th>
<th scope="col">Image</th>
<th scope="col">Action</th>
</tr>
</thead>
<tbody>
{product.map((item) => (
<tr>
<td>{item.productName}</td>
<td>{item.brand}</td>
<td>{item.category}</td>
<td>{item.productDescription}</td>
<td>{item.pricePerUnit}</td>
<td>{item.availableStock}</td>
<td>{item.reservedStock}</td>
<td>{item.shippedStock}</td>
<td>
<img src={item.imageUrl} height={100} width={100} />
</td>
<td>
<Button>
onClick={() => {
onDeleteProduct();
}}
style={{ color: "red", marginLeft: 12 }}
/Button>
</td>
</tr>
))}
</tbody>
</table>
</div>
);
}
}
I've already done the part of GET method to fetch all the data from API to the table.
Now I'm working on the DELETE method. I've also already created a delete button in each row. But I have no idea how to get the upc value in the row that I click the delete button to call an API http://localhost:8080/api/inventory/deleteproduct.
Can someone give me some idea, please?
Since each item has a unique upc, then your function should accept this as an argument
<td>
<Button>
onClick={() => {
onDeleteProduct(item.upc);
}}
style={{ color: "red", marginLeft: 12 }}
/Button>
</td>
and then your method would become like this
onDeleteProduct = itemUpc => {
axios.delete('http://localhost:8080/api/inventory/deleteproduct', { data: { upc: itemUpc }, headers: { } });
}
This is my Table.js file code.
In this component i pass UserData which hold data that come from the server, handleEditButton method for update my data and handleDeleteButton for delete my data. When UserData is empty than i'm return "No data found" other wise it's show's data in tabular format
const Table = ({ UserData, handleEditButton, handleDeleteButton }) => {
if (UserData == '') {
return (
<>
{
<h2>N Data Found</h2>
}
</>
)
}
else {
return (
<>
{
<table cellSpacing={0} cellPadding={0} className={tableStyles.details}>
<thead>
<tr>
<th className={tableStyles.table}>Id</th>
<th className={tableStyles.table}>Name</th>
<th className={tableStyles.table}>Address</th>
<th className={tableStyles.table}>E-mail</th>
<th className={tableStyles.table}>Mobile No</th>
<th className={tableStyles.table}>Gender</th>
<th className={tableStyles.table}>City</th>
<th className={tableStyles.table}>Action</th>
</tr>
</thead>
<tbody>
{
(UserData && UserData.map((user) => (
<tr>
<th key={user.id}>{user.id}</th>
<td className={tableStyles.name}>{user.name}</td>
<td className={tableStyles.address}>{user.address}</td>
<td className={tableStyles.mail}>{user.mail}</td>
<td>{user.no}</td>
<td>{user.gender}</td>
<td>{user.city}</td>
<td colSpan={2} className={tableStyles.btnGroup}>
<button className={tableStyles.editBtn} onClick={(e) => { handleEditButton(user.id) }}>Edit</button>
<button className={tableStyles.deleteBtn} onClick={(e) => { handleDeleteButton(user.id) }}>Delete</button>
</td>
</tr>
)))
}
</tbody>
</table>
}
</>
)
}
}
You missed adding a ternary condition.
You can check with the following code.
const Table = ({ UserData, handleEditButton, handleDeleteButton }) => {
{
UserData == "" ? (
<h2>No Data Found</h2>
) : (
<table cellSpacing={0} cellPadding={0} className={tableStyles.details}>
<thead>
<tr>
<th className={tableStyles.table}>Id</th>
<th className={tableStyles.table}>Name</th>
<th className={tableStyles.table}>Address</th>
<th className={tableStyles.table}>E-mail</th>
<th className={tableStyles.table}>Mobile No</th>
<th className={tableStyles.table}>Gender</th>
<th className={tableStyles.table}>City</th>
<th className={tableStyles.table}>Action</th>
</tr>
</thead>
<tbody>
{UserData &&
UserData.map((user) => (
<tr>
<th key={user.id}>{user.id}</th>
<td className={tableStyles.name}>{user.name}</td>
<td className={tableStyles.address}>{user.address}</td>
<td className={tableStyles.mail}>{user.mail}</td>
<td>{user.no}</td>
<td>{user.gender}</td>
<td>{user.city}</td>
<td colSpan={2} className={tableStyles.btnGroup}>
<button
className={tableStyles.editBtn}
onClick={(e) => {
handleEditButton(user.id);
}}
>
Edit
</button>
<button
className={tableStyles.deleteBtn}
onClick={(e) => {
handleDeleteButton(user.id);
}}
>
Delete
</button>
</td>
</tr>
))}
</tbody>
</table>
);
}
};
const SheetTable = ({ sheets }) => {
return (
<table className="sheetTableComponent">
<thead>
<tr>
<td>No</td>
<td>track</td>
<td>item</td>
</tr>
</thead>
<tbody>
{sheets.map((item, index) => (
<tr key={index}>
<td>{index}</td>
<td>
<div>{item.code}</div>
</td>
<td>
<div>{item.item}</div>
</td>
</tr>
))}
</tbody>
</table>
)
}
This is my table. After populate it got about 10 rows. I want if one row click, it will highlight, the other rows un-highlight
Hope it will solve your problem.
Are you looking for something like this?
changeColor = (id) => {
this.setState({ selected: id });
};
render() {
const { selected, arr } = this.state;
return (
<table className="sheetTableComponent">
<thead>
<tr>
<td>No</td>
<td>track</td>
<td>item</td>
</tr>
</thead>
<tbody>
{arr.map((item, index) => (
<tr
key={index}
style={{
color: selected === item.id ? "red" : ""
}}
onClick={() => this.changeColor(item.id)}
>
<td>{index}</td>
<td>
<div>{item.code}</div>
</td>
<td>
<div>{item.item}</div>
</td>
</tr>
))}
</tbody>
</table>
);
}
Live working demo
Couple of ways to do it, but most simple is to just use css
Assign tabindex to your rows and use :focus selector to highlight the row
<tr key={index} className="row" tabindex="0">
CSS:
.row:focus {
outline: none;
background: green;
}
i have a problem that i need to add the data from state and loop it using map. in my project im using redux and got the value from redux its self but in the state won't render again after map.
i already tried to using this.props.sendNameProduct in my array of map but when i added the new product the first product updated with the value of last product. i just want it to store the first product and then when im inputting the second product , the first product still there.
class OpenPositions extends Component {
constructor(props) {
super(props);
this.state = {};
}
render() {
console.log(this.props, "ini porpoaspdopa")
console.log(this.props.sendNameProduct, "ini send name")
console.log(this.props.sendNameProduct.sendNameProduct," ini kirik");
let dapetItem = this.props.cobaSend == null ? [] : this.props.cobaSend
let cobaSend = [{qty: '123'}];
let getItem = localStorage.getItem('storage')
let newData =[];
let newDataBaru = [];
let newArr = [];
newArr.push(this.props.cobaSend);
newData = newDataBaru.concat(newArr)
console.log(newArr, "ini new array");
console.log(newData, "ini new Data")
return (
<div style={{height:'100%', overflow:'auto'}}>
<table className="borderline" cellspacing="0" cellpadding="0" border="0" style={{height:'100%'}}>
<tbody>
<tr>
<td>
<div>
<div>
<table style={{height:"100%", width:"100%"}}>
<tbody>
<tr align="center" className="fieldtitle fieldbg">
<td align="left">Items</td>
<td>Qty</td>
<td>Sold</td>
<td>Bought</td>
<td>Avail</td>
<td>Date</td>
<td>Options</td>
</tr>
</tbody>
<tbody className="divOP2">
{this.props.cobaSend.map((item, index) =>{
console.log(item, "ini item bois");
console.log(index, "ini index")
return(
<tr align="center" className="contentbg">
<td align="left" nowrap className="bggradientleft" style={{backgroundImage: ' url(https://demo.sgberjangka.com/images/background_gradientleft.gif)', backgroundRepeat: 'repeat-y', backgroundRepeatX: 'repeat', boxSizing: "border-box", border: "1px solid black", backgroundSize:"100%"}}><font color="#FFFFFF"><strong>{item.product}</strong></font></td>
<td>{item.qty}</td>
<td>{item.sell}</td>
<td>{item.buy}</td>
<td>{item.avail}</td>
<td>{item.date}</td>
<td>
<input
className="checkbox"
type="checkbox"
checked={this.state.isChecked}
onChange={this.handleCheckBox}
/>
</td>
</tr>
)})}
</tbody>
</table>
</div>
</div>
</td>
</tr>
<table className="normal" cellspacing="0" cellpadding="0" border="0" style={{height:'100%'}}>
<tbody>
<tr>
<td>
<button type="submit" className="normalButton wide">GTC Order (Liq)</button>
</td>
<td>
<button type="submit" className="normalButton wide">Buy/Sell (Liq)</button>
</td>
</tr>
</tbody>
</table>
</tbody>
</table>
</div>
)
}
};
function stateProps(state){
console.log(state.main.sendNameProduct, "ini send Name Product")
console.log(state.main.sendValueSell, "ini send sell Product")
console.log(state.main.sendValueBuy, "ini send buy Product")
console.log(state.main.sendQuantity, "ini send qty Product")
return {
sendNameProduct : state.main,
sendValueSell : state.main,
sendValueBuy : state.main,
sendQuantity : state.main
};
};
function dispatchProps(dispatch){
return {
}
}
export default connect(
stateProps,
dispatchProps
)(OpenPositions);
the result its when im updating with new data the first one changed and got same values with new data.
lets assume with this.props.cobaSend got the objects like {product: "HKK50_BBJ", qty: "12", sell: "28579", buy: "--", avail: "12", …}, in mapping got the value product, qty ,sell ,and etc. but when im inserting the new data the value in map not updateing with the new array.
Your newData.map loop on the newData array, but display this.props.sendNameProduct... values in your DOM.
Might just be an error on accessing those values, try call the item return by the map callback :
{
newData.map((item, index) =>{
console.log(item, "ini item bois");
console.log(index, "ini index")
return(
<tr align="center" className="contentbg">
<td align="left" nowrap className="bggradientleft"><font color="#FFFFFF"><strong>{item.item}</strong></font></td>
<td>{item.qty}</td>
<td>{item.sell}</td>
<td>{item.buy}</td>
<td>{item.date}</td>
<td>{item.avail}</td>
<td>
<input
className="checkbox"
type="checkbox"
checked={this.state.isChecked}
onChange={this.handleCheckBox}
/>
</td>
</tr>
)
});
}
class OpenPositions extends Component {
constructor(props) {
super(props);
this.state = {
newArr : []
};
}
render() {
console.log(this.props, "ini porpoaspdopa")
console.log(this.props.sendNameProduct, "ini send name")
console.log(this.props.sendNameProduct.sendNameProduct," ini kirik");
console.log(this.props.cobaSend," ini COBA SEND");
// let dapetItem = this.props.cobaSend == null ? [] : this.props.cobaSend
// let cobaSend = [{qty: '123'}];
// let getItem = localStorage.getItem('storage')
let newArr = this.state.newArr;
newArr.push(this.props.cobaSend);
console.log(newArr, "ini new array");
console.log(newData, "ini new Data")
//let newData = [];
//let newDataBaru = newData.concat(data);
//newData.push(data[0])
//console.log(newData, "ini new Data")
//console.log(newDataBaru,"ini data baru")
//newData = newDataBaru.concat(data)
// for(let i =0 ; i< 5; i++){
// }
//console.log(newData, "ini new Data")
return (
<div style={{height:'100%', overflow:'auto'}}>
<table className="borderline" cellspacing="0" cellpadding="0" border="0" style={{height:'100%'}}>
<tbody>
<tr>
<td>
<div>
<div>
<table style={{height:"100%", width:"100%"}}>
<tbody>
<tr align="center" className="fieldtitle fieldbg">
<td align="left">Items</td>
<td>Qty</td>
<td>Sold</td>
<td>Bought</td>
<td>Avail</td>
<td>Date</td>
<td>Options</td>
</tr>
</tbody>
<tbody className="divOP2">
{newArr.map((item, index) =>{
console.log(item, "ini item bois");
console.log(index, "ini index")
return(
<tr align="center" className="contentbg">
<td align="left" nowrap className="bggradientleft" style={{backgroundImage: ' url(https://demo.sgberjangka.com/images/background_gradientleft.gif)', backgroundRepeat: 'repeat-y', backgroundRepeatX: 'repeat', boxSizing: "border-box", border: "1px solid black", backgroundSize:"100%"}}><font color="#FFFFFF"><strong>{item.product}</strong></font></td>
<td>{item.qty}</td>
<td>{item.sell}</td>
<td>{item.buy}</td>
<td>{item.avail}</td>
<td>{item.date}</td>
<td>
<input
className="checkbox"
type="checkbox"
checked={this.state.isChecked}
onChange={this.handleCheckBox}
/>
</td>
</tr>
)})}
</tbody>
</table>
</div>
</div>
</td>
</tr>
<table className="normal" cellspacing="0" cellpadding="0" border="0" style={{height:'100%'}}>
<tbody>
<tr>
<td>
<button type="submit" className="normalButton wide">GTC Order (Liq)</button>
</td>
<td>
<button type="submit" className="normalButton wide">Buy/Sell (Liq)</button>
</td>
</tr>
</tbody>
</table>
</tbody>
</table>
</div>
)
}
};
im using state to store it there and then when im inputting the data its worked.
Can anyone suggest me good modal popup for reactjs and ? I want it for delete confirmation. I tried react-foundation-apps 's modal, but due to less documentation i am unable to use it for delete functionality in tabular data.
var React = require('react');
var EmployeeList = React.createClass({
render: function() {
var employees = this.props.employees.map(function(e, i){
return (
<tr key={i}>
<td>{e.employeeName}</td>
<td><a title="edit" href="#"><i className="fi-pencil"></i></a></td>
<td>
<a title="delete" href="#"><i className="fi-trash"></i></a>
</td>
</tr>
)
}, this);
return (
<div>
<table id="users">
<thead>
<tr>
<th>Employee</th>
<th>Edit</th>
<th>Delete</th>
</tr>
</thead>
<tbody>
{employees}
</tbody>
</table>
</div>
);
}
});
module.exports = EmployeeList;
Plus
Suggest me good datatable/datagrid for reactjs with foundation.
A model is a simple pattern you can build yourself. The main attributes are absolute positioning, show/hide and high zIndex. Here is an example.
import React from 'react';
import Actions from '../../flux/Actions';
import TreeViewB from './../common/jTreeViewB';
let JumpListSty = {
backgroundColor: '#e1ded5',
left: '20px',
maxHeight: '80%',
overflow: 'auto',
position: 'absolute',
top: '30px',
width: '350px',
zIndex: '100'
};
export default class JumpList extends React.Component {
clickHandler = (node) => { Actions.selectJumpNode(node); Actions.appActions('jump'); }
render() {
if (this.props.hide) return null;
let options = {
icon: {sun: 1, leaf: 2, snow: 3},
typeName: ['node', 'nodeLevel']
};
let isMobile = (this.props.appState.deviceType == 'mobile');
return (
<div id='JumpListSty' style={JumpListSty}>
<TreeViewB data={this.props.data} options={options} titleClick={this.clickHandler} mobile={isMobile} />
</div>
);
}
}
<JumpList data={jumpData} appState={this.props.appState} hide={hideJump} />
A datagrid is a simple pattern also. It is a arrangement of columns contained in a map of rows. You can use an html table or not.
function dataMap(item, index) {
return (
<tr key={item._id + index}>
<td ></td>
<td style={columnSty}>{item.userinclude}</td>
<td style={columnSty}>{item.domaininclude}</td>
<td style={columnSty}>{item.userexclude}</td>
<td style={columnSty}>{item.domainexclude}</td>
<td style={columnSty}>{item.userskip}</td>
<td style={columnSty}>{item.domainskip}</td>
<td style={lastColumnSty}>{item._id}</td>
</tr>
)
}
export default class AggregateList extends React.Component {
render() {
let list = this.props.data.map(dataMap);
return (
<div id='AggregateListSty' style={AggregateListSty}>
<table >
<thead>
<tr>
<th ></th>
<th style={columnHeaderSty}></th>
<th style={columnHeaderSty}>Protested</th>
<th style={columnHeaderSty}></th>
<th style={columnHeaderSty}>Excluded</th>
<th style={columnHeaderSty}></th>
<th style={columnHeaderSty}>Skipped</th>
<th style={lastColumnSty}></th>
</tr>
<tr>
<th ></th>
<th style={columnHeaderSty}>User</th>
<th style={columnHeaderSty}>All</th>
<th style={columnHeaderSty}>User</th>
<th style={columnHeaderSty}>All</th>
<th style={columnHeaderSty}>User</th>
<th style={columnHeaderSty}>All</th>
<th style={lastColumnSty}></th>
</tr>
</thead>
<tbody>
{list}
</tbody>
</table>
</div>
);
}
}