im creating an array for list cart items, works well, but wanted to know how can i access to each item properties to create the total order amount outside table item
<Table className={classes.table} aria-label="simple table">
<TableHead>
<TableRow>
<TableCell className={classes.hideOnMobile}>
</TableCell>
<TableCell>PRODUCTO</TableCell>
<TableCell>PRECIO</TableCell>
<TableCell align="center">CANTIDAD</TableCell>
<TableCell align="right">TOTAL</TableCell>
<TableCell align="right"></TableCell>
</TableRow>
</TableHead>
<TableBody>
{data.map((row) => (
<Item data={row} {...props} />
))}
</TableBody>
<TableFooter className={classes.table}>
<TableCell>
</TableCell>
<TableCell align="right">TOTAL ORDER</TableCell>
<TableCell align="left">"TOTAL GOES HERE"</TableCell>
</TableFooter>
</Table>
This is my JSON data
0:
id: 31
image: "https://example.com/test.jpg"
name: "Product name 1"
price: 3
quantity: 13
total: 39
__proto__: Object
1: {id: 2, name: "Product name 2", price: 3, …}
length: 2
I would have a total variable somewhere in the component (a class property in this example, could very well just be a variable if you are using functional components), and accumulate the total as you loop over your data. That way, you only have to loop over your data set once. Something like this:
class App extends React.Component {
data = {/* your data */}
total = 0;
render() {
return (
<Table className={classes.table} aria-label="simple table">
<TableHead>
<TableRow>
<TableCell className={classes.hideOnMobile}>
</TableCell>
<TableCell>PRODUCTO</TableCell>
<TableCell>PRECIO</TableCell>
<TableCell align="center">CANTIDAD</TableCell>
<TableCell align="right">TOTAL</TableCell>
<TableCell align="right"></TableCell>
</TableRow>
</TableHead>
<TableBody>
{this.data.map((row) => (
this.total += row.total;
return <Item data={row} {...props} />
))}
</TableBody>
<TableFooter className={classes.table}>
<TableCell>
</TableCell>
<TableCell align="right">TOTAL ORDER</TableCell>
<TableCell align="left">{this.total}</TableCell>
</TableFooter>
</Table>
);
}
Related
I want to create a cell for each value of my array which is stored in a array of objects but what is going on is all the data which is in the array which is inside the object is not getting rendered as individual table cell. How to achieve
import {Paper,Table,TableBody,TableCell,TableContainer,TableHead,TableRow} from "#mui/material";
export function Schedule(prop){
let data = prop.data
console.log(data)
return(
<>
{!data ? "" :
<TableContainer>
{data.map((result) =>(
<Table>
<TableHead>
<TableRow>
<TableCell>Fact Name</TableCell>
<TableCell>{result.slotFree}</TableCell>
</TableRow>
</TableHead>
<TableBody>
<TableRow>
<TableCell>
{result.name}
</TableCell>
<TableCell>
{result.status}
</TableCell>
</TableRow>
</TableBody>
</Table>
))}
</TableContainer>
}
</>
)
}[![This is my incoming data array of object](https://i.stack.imgur.com/sygfU.png)](https://i.stack.imgur.com/sygfU.png)
that result
I want that each free slot comes as an individual cell and should not render out in the same line This is the output](https://i.stack.imgur.com/jMTFC.png)
I want the time and slot status to be in the same column
I've got this table rendering this APP_DATA object. But I want to have the number of rows as a column (header left blank on purpose), how would i dynamically render the number next to each row?
bare in mind, since only "prt" and "cat" are arrays, you can only use Array methods on those.
i really appreciate any help
const API_DATA = [
{
"bnd": "test brand 11",
"url": "htttps://www.test.com/all-products11",
"cnt": "UK",
"prt": ['Perf. Supps'],
"cat": ['Keto']
},
{
"bnd": "test brand 12",
"url": "htttps://www.test.com/all-products12",
"cnt": "UK",
"prt": ['Diet. Supps'],
"cat": ['Gaming']
},
]
// table
return (
<>
<TableBody >
{filteredData(props.API_DATA,props.filters).map(row => (
<TableRow key={row.name}>
<TableCell style={{ textAlign:"left"}} align="center">{row.bnd}</TableCell>
<TableCell style={{ textAlign:"left"}} align="center">{row.bnd}</TableCell>
<TableCell style={{ textAlign:"left"}} align="center">{row.cnt}</TableCell>
<TableCell style={{ textAlign:"left"}} align="center">{row.prt.map((e) => <span style={{padding: "5px"}} key={e} >{`${e + ','}`}</span>)}</TableCell>
<TableCell style={{ textAlign:"left"}} align="center">{row.cat}</TableCell>
<TableCell style={{ textAlign:"left"}} align="center"><a href={row.url}>{row.url}</a></TableCell>
</TableRow>
))}
</TableBody>
</>
)
map method provide you the index as a second argument . since the index starts with 0 you can do index + 1 . so that the rownum starts with 1 .
<TableBody >
{filteredData(props.API_DATA,props.filters).map((row, index) => (
<TableRow key={row.name}>
<TableCell style={{ textAlign:"left"}} align="center">{index + 1}</TableCell>
.....
</TableRow>
))}
</TableBody>
Working Code :https://codesandbox.io/s/broken-https-2i454?file=/src/App.js
I'm using Material UI in my reactjs project and I'm trying the update the value entered inside a textfield of a table using onChange function for the textfield, currently the value is present inside an array of array,I want to update the componentQuantity , I'm aware of passing the event to get the event.target.value , but what is the correct way to update the specific value of the textfield present inside a array of array. Please someone help me out here.
class TabData extends Component {
constructor(props) {
super(props);
this.state = {
loading: true,
data: [
{
BomComponentCode: "345543",
BomComponentName: "COMP1",
BomComponentRefUOM: "gm",
rowId: 0,
consumptionBatchNumbers: [
{
componentBatchNumber: "20",
componentQuantity: 2
},
{
componentBatchNumber: "21",
componentQuantity: 3
}
]
},
//2nd cloumn
{
BomComponentCode: "5543",
BomComponentName: "COMP2",
BomComponentRefUOM: "KG",
rowId: 1,
consumptionBatchNumbers: [
{
componentBatchNumber: "22",
componentQuantity: 4
},
{
componentBatchNumber: "23",
componentQuantity: 5
}
]
}
],
renderState: false
};
}
handleUpdate = (index, Code) => {
this.setState({
renderState: Code
});
};
handleChange = (e) => {
console.log(e.target.value)
};
render() {
const { classes } = this.props;
const { data, renderState } = this.state;
return (
<div className={classes.list}>
<React.Fragment>
<Grid
item
xs={12}
sm={12}
md={12}
className={classes.grid}
style={{ paddingLeft: "0" }}
>
<p variant="h6" className={classes.font}>
Table Details
</p>
<span className={classes.borders}></span>
</Grid>
<div>
<TableContainer component={Paper} className={classes.paper}>
<Table className={classes.table} aria-label="collapsible table">
<TableHead>
<TableRow>
<TableCell> Number</TableCell>
<TableCell> Text</TableCell>
<TableCell>UOM</TableCell>
<TableCell> Batch </TableCell>
<TableCell> Quantity</TableCell>
<TableCell>Actions</TableCell>
</TableRow>
</TableHead>
<TableBody>
<React.Fragment>
{data.map((item, i) => (
<React.Fragment>
<TableRow key={i}>
<TableCell scope="row" align="left">
{item.BomComponentCode}
</TableCell>
<TableCell align="left">
{item.BomComponentName}
</TableCell>
<TableCell align="left">
{item.BomComponentRefUOM}
</TableCell>
<TableCell>
{item.consumptionBatchNumbers.map((row, i) => (
<div key={i}>
<TableCell align="left">
{row.componentBatchNumber}
</TableCell>
</div>
))}
</TableCell>
{renderState === item.BomComponentCode ? (
<TableCell align="left">
{item.consumptionBatchNumbers.map((row, indi) => (
<div key={indi}>
<input
// value={row.componentQuantity}
onChange={(e) =>
this.handleChange(e)
}
defaultValue={row.componentQuantity}
/>
</div>
))}
</TableCell>
) : (
<TableCell align="left">
{item.consumptionBatchNumbers.map((row, indi) => (
<div key={indi}>
<TableCell align="left">
{row.componentQuantity}
</TableCell>
</div>
))}
</TableCell>
)}
<TableCell>
<button
onClick={() =>
this.handleUpdate(i, item.BomComponentCode)
}
>
Update
</button>
</TableCell>
</TableRow>
</React.Fragment>
))}
</React.Fragment>
</TableBody>
</Table>
</TableContainer>
</div>
<Grid container justify="center">
<Grid
item
xs={4}
sm={4}
md={2}
style={{
textAlign: "center",
padding: "1rem"
}}
>
<button >Close</button>
</Grid>
</Grid>
</React.Fragment>
</div>
);
}
}
export default (TabData);
To modify the value in the deeply nested array you need indexes . Once you have the indexes its easier to change the values .
Change the handleChange method to accept the row and deeply nested row's indexes.
onChange={(e) => this.handleChange(e, i, indi)}
Once you have the indexes we can deep clone the original state to create a new copy of state and mutate it directly .
handleChange = (e, rowIndex, consumptionBatchIndex) => {
// deep clone the data
const clonedData = JSON.parse(JSON.stringify(this.state.data));
clonedData[rowIndex].consumptionBatchNumbers[
consumptionBatchIndex
].componentQuantity = e.target.value;
this.setState({
data: clonedData
});
};
Now we can read the value in the input as
<input
value={row.componentQuantity}
onChange={(e) => this.handleChange(e, i, indi)}
/>
so I have this Table I've rendered its rows from an array map as shown below
<TableContainer component={Paper}>
<Table className={classes.table} aria-label="simple table">
<TableHead>
<TableRow>
<TableCell>Object Name</TableCell>
<TableCell align="center">Object Field and Values</TableCell>
</TableRow>
</TableHead>
<TableBody>
{union &&
unionArray.map((row) => (
<TableRow key={row.name}>
<TableCell component="th" scope="row">
{row.name}
</TableCell>
{Object.keys(row).map((key) =>
key === "name" ? (
""
) : (
<TableCell align="center">
{/*insert dropdown select*/}
<FormControl
variant="outlined"
className={classes.formControl}
>
<InputLabel htmlFor="outlined-age-native-simple">
Values
</InputLabel>
<Select
native
label="Value"
>
<option aria-label="None" value="" />
<option>{key}:{row[key]}</option>
</Select>
</FormControl>
</TableCell>
)
)}
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
the array of objects where I mapped from is shown below. i.e UnionArray
my problem is the rows that have a third key/value pair are rendering as entire table cell, I just want them to be part of the dropdown. the output now is something like this
you could modify your array you get from the api and do sth like this:
let modifiedUnion = unionArray.map(el=>{
let tempObj={}
let values=[]
Object.keys(el).map(key=>
if(key!=="name"){
tempObj.values = values.push({[key]:el[key]})
}else{
tempObj.name = el.name
}
return tempObj
})
and after that write this part like this:
{modifiedUnion.map((row) => (
<TableRow key={row.name}>
<TableCell align="center">
{row.name}
</TableCell>
<TableCell align="center">
<FormControl variant="outlined" className={classes.formControl}>
<InputLabel htmlFor="outlined-age-native-simple">
Values
</InputLabel>
<Select native label="Value">
<option aria-label="None" value="" />
{row.values.map((key) =>
<option>{Object.keys(key)[0]}:{Object.values(key)[0]}</option>
)}
</Select>
</FormControl>
</TableCell>
</TableRow>
))}
I don't have enough reputations to comment but the answer lies in #lakshya's response and #ahmed's comment. Object.keys will return null for when key === 'name' but it will return valid JSX for when the keys aren't name, hence, your table cell having 2 dropdowns.
As for how to go about formatting the response, you can format your loop like in the image attached.
Convert the object to a format like
[{
name: 'obj1',
values: [
{
a: 1
}
]
},
{
name: 'obj3',
values: [
{
c: 2,
d: 5
}
]
}
]
I am trying to access all elements of my array except the first one but i get empty values.
renderTableBody = thisService => {
console.log(thisService); // in the image it's the printed array
console.log(thisService.length); // in the image is the number 1
return thisService.slice(1).map(item =>
item.map(k => (
<TableRow key={k.kpiId}>
<TableCell align="left" component="th" scope="row">
{k.kpiId}
</TableCell>
<TableCell align="left">{k.kpiName}</TableCell>
<TableCell align="left">{k.targetDisplay}</TableCell>
<TableCell align="left">{k.targetDisplay}</TableCell>
<TableCell align="left">{k.reason}</TableCell>
<TableCell align="left">{k.action}</TableCell>
<TableCell align="left">{k.dueDate}</TableCell>
<TableCell align="left">{k.owner}</TableCell>
</TableRow>
))
);
};
When i log the length of array it prints 1 when it actually has 2 elements. When i try to access only the second element of the array, i get "undefined".
This is the logged to console object:
Am i doing something wrong in accessing the second element of my array which is an array itself?
EDIT
The part of code where i am calling the function renderTableBody:
<div id="servicesInputs">
{kpiServInputs.map((service) => (
<div key={service[0].id} id={service[0].id}>
<div align="left">
<h4>{service[0].serviceName}</h4>
</div>
<div>
<Paper >
<Table>
<TableHead>
<TableRow>
<TableCell align="left">#</TableCell>
<TableCell align="left">KPI</TableCell>
<TableCell align="left">Target</TableCell>
<TableCell align="left">Actual</TableCell>
<TableCell align="left">Reason</TableCell>
<TableCell align="left">Action</TableCell>
<TableCell align="left">Due Date</TableCell>
<TableCell align="left">Owner</TableCell>
</TableRow>
</TableHead>
<TableBody>
{this.renderTableBody(service)}
</TableBody>
</Table>
</Paper>
<br/>
</div>
</div>
))}
</div>
renderTableBody = thisService => {
console.log(thisService); // in the image it's the printed array
console.log(thisService.length); // in the image is the number 1
return thisService[1].map(item =>
item.map(k => (
<TableRow key={k.kpiId}>
<TableCell align="left" component="th" scope="row">
{k.kpiId}
</TableCell>
<TableCell align="left">{k.kpiName}</TableCell>
<TableCell align="left">{k.targetDisplay}</TableCell>
<TableCell align="left">{k.targetDisplay}</TableCell>
<TableCell align="left">{k.reason}</TableCell>
<TableCell align="left">{k.action}</TableCell>
<TableCell align="left">{k.dueDate}</TableCell>
<TableCell align="left">{k.owner}</TableCell>
</TableRow>
))
);
};
This should be your code because as #Dupocas pointed out, thisService is an array that looks like [{Object}, [Array]].
When you run slice on this and a map on the result, what you are doing is trying to map through the outer array of something like [['stuff you need']]. This outer array has a length of 1 and would act exactly as you are seeing it act. By changing the slice to directly access the first index of thisService, you will be looping though the info you need.
The problem was that the array was populated asynchronously with making a fetch call to an api. What worked for me was making the return async and waiting the fetch call to finish and then populating the array.
The code:
function fetchKpiServicesInputs(state) {
let serviceInputs = [];
return async dispatch => {
for (var i = 0; i < servicesCount; i++) {
let newServ = [];
newServ.push({id: i, serviceName: kpiServices[i].name });
let url = "apiUrl";
const response = await fetch(url, {
method: 'GET'
});
const responseData = await response.json();
if (Object.keys(responseData).length > 0) {
newServ.push(responseData);
}
serviceInputs.push(newServ);
}
dispatch(receiveKpiServiceInputs(serviceInputs));
};
Thanks for the help everyone!