Customize which TableRows appear on which page using TablePagination (Material-ui) - javascript

I want to be able to set whatever table row I want to a specific page. For example, If I have three TableRows and want the first two on page one in my DataTable and the third one on page two. I'm new to programming so the more thorough the explanation the better. Here is a quick peek at my code.
I have the rows in the TableBody inside the TableContainer:
<TableRow className="property_taxes" hover>
<TableCell>Property Taxes</TableCell>
<TableCell align="right">0</TableCell>
<TableCell align="right">0</TableCell>
<TableCell align="right">0</TableCell>
</TableRow>
<TableRow className="maintenance" hover>
<TableCell>Maintenance</TableCell>
<TableCell align="right">0</TableCell>
<TableCell align="right">0</TableCell>
<TableCell align="right">0</TableCell>
</TableRow>
<TableRow className="total_costs" hover>
<TableCell>Total</TableCell>
<TableCell align="right">0</TableCell>
<TableCell align="right">0</TableCell>
<TableCell align="right">0</TableCell>
</TableRow>
And then I have the TablePagination right after that:
<TablePagination
component="div"
count={7}
rowsPerPage={rowsPerPage}
rowsPerPageOptions={[]}
page={page}
onChangePage={handleChangePage}
/>
Thank you in advance!
export default function DataTable() {
const classes = useStyles();
const [page, setPage] = React.useState(0);
const handleChangePage = (event, newPage) => {
setPage(newPage)
}
return (
<div>
<TableContainer component={Paper} className={classes.container}>
<Table stickyHeader className={classes.table} aria-label="simple table">
<TableHead>
<TableRow>
<TableCell>Expenses</TableCell>
<TableCell align="right">Monthly ($)</TableCell>
<TableCell align="right">Yearly ($)</TableCell>
<TableCell align="right">Total ($)</TableCell>
</TableRow>
</TableHead>
<TableBody className={classes.tableBody}>
<TableRow className="principle" hover>
<TableCell id="name">Principle</TableCell>
<TableCell id="monthly"align="right">0</TableCell>
<TableCell id="yearly"align="right">0</TableCell>
<TableCell id="total"align="right">0</TableCell>
</TableRow>
<TableRow className="private_mortgage_insurance" hover>
<TableCell>Private Mortgage Insurance</TableCell>
<TableCell align="right">0</TableCell>
<TableCell align="right">0</TableCell>
<TableCell align="right">0</TableCell>
</TableRow>
<TableRow className="interest" hover>
<TableCell>Interest</TableCell>
<TableCell align="right">0</TableCell>
<TableCell align="right">0</TableCell>
<TableCell align="right">0</TableCell>
</TableRow>
<TableRow className="property_taxes" hover>
<TableCell>Property Taxes</TableCell>
<TableCell align="right">0</TableCell>
<TableCell align="right">0</TableCell>
<TableCell align="right">0</TableCell>
</TableRow>
<TableRow className="maintenance" hover>
<TableCell>Maintenance</TableCell>
<TableCell align="right">0</TableCell>
<TableCell align="right">0</TableCell>
<TableCell align="right">0</TableCell>
</TableRow>
<TableRow className="total_costs" hover>
<TableCell>Total</TableCell>
<TableCell align="right">0</TableCell>
<TableCell align="right">0</TableCell>
<TableCell align="right">0</TableCell>
</TableRow>
<TableRow className="closing_costs" hover>
<TableCell>Closing Costs</TableCell>
<TableCell align="right">0</TableCell>
<TableCell align="right">0</TableCell>
<TableCell align="right">0</TableCell>
</TableRow>
</TableBody>
</Table>
</TableContainer>
<TablePagination
component="div"
count={7}
rowsPerPage={6}
rowsPerPageOptions={[]}
page={page}
onChangePage={handleChangePage}
/>
</div>
);
}

Related

How to adjust height of material UI header with styles

How can you style the header of a MUI table like height and width?
<TableHead >
<TableRow >
<TableCell hover>Dessert (100g serving)</TableCell>
<TableCell align="right">Calories</TableCell>
<TableCell align="right">Fat (g)</TableCell>
<TableCell align="right">Carbs (g)</TableCell>
<TableCell align="right">Protein (g)</TableCell>
</TableRow>
</TableHead>
I tried passing
sx={{ height:'20px' }}
but the height is fixed
You can achieve that by using sx on the TableHead component:
<TableHead sx={{height:"150px"}}>
<TableRow >
<TableCell hover>Dessert (100g serving)</TableCell>
<TableCell align="right">Calories</TableCell>
<TableCell align="right">Fat (g)</TableCell>
<TableCell align="right">Carbs (g)</TableCell>
<TableCell align="right">Protein (g)</TableCell>
</TableRow>
</TableHead>
To customize the styling of the TableHead you need to target the MuiTableCell-head class of the Table.
One important thing to notice, Mui TableHead height is not coming from the height property, It is coming from line-height. Please check the example below:
import { Table, TableHead, TableBody } from '#mui/material'
<Table sx={{ '& .MuiTableCell-head':{ lineHeight: 20, color: 'red' } }}>
<TableHead>
</TableHead>
<TableBody>
</TableBody>
</Table>

How can I expand the row only when that row was clicked?

I have this materia-ui table. Every time I'll click the button to expand the row1, it will also expand the second row. How can I fix this where only that specific row will expand?
<Table stickyHeader aria-label="sticky table">
<TableHead>
<TableRow hover>
<TableCell>Title</TableCell>
<TableCell>Created Date</TableCell>
</TableRow>
</TableHead>
<TableBody>
{data &&
data((index) => (
<TableRow hover>
<TableCell>
<IconButton
aria-label="expand row"
size="small"
onClick={() => setOpen(!open)}
>
{open ? (
<KeyboardArrowUpIcon />
) : (
<KeyboardArrowDownIcon />
)}
</IconButton>
</TableCell>
<TableCell component="th" scope="row">
{index.title}
</TableCell>
<TableCell component="th" scope="row">
{new Date(
index.createdDate.seconds * 1000
).toDateString()}
</TableCell>
<TableCell colSpan={6}>
<Collapse in={open} timeout="auto" unmountOnExit>
{index.text}
</Collapse>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
Wrap TableRow in a component
const Row = ({item}) => {
const [open, setOpen] = useState(false);
return <TableRow>...</TableRow>
}
<TableBody>
{data.map((item, index) => (
<Row key={index} item={item} />
))}
</TableBody>

ReactJS table with material ui

I am trying to use the material UI minimized table to create a dashboard https://material-ui.com/pt/components/tables/
I ran into an issue that I'm stuck with for the last 5 hours. I could successfully render the data from my database to display in the table. However, when I retrieve the data using the map function, all is displayed in one single row x5.
Picture: Front-end view
I'm trying to display the name and data in different rows and not "Sue Flavio John Doe rajid" because each is a different object.
I'd appreciate some help to understand where is my logical mistake.
function EmployeeList() {
const [employeeList, setEmployeeList] = useState([]);
console.log(employeeList);
useEffect(() => {
Axios.get("http://localhost:4000/vacations_cs_read").then((response) => {
setEmployeeList(response.data);
});
}, []);
const Row = () => {
const [open, setOpen] = React.useState(false);
const classes = useRowStyles();
return (
<React.Fragment>
<TableRow className={classes.root}>
<TableCell>
<IconButton
aria-label="expand row"
size="small"
onClick={() => setOpen(!open)}
>
{open ? <KeyboardArrowUpIcon /> : <KeyboardArrowDownIcon />}
</IconButton>
</TableCell>
<TableCell component="th" scope="row">
{employeeList.map((val, key) => {
return <td>{val.employeeName}</td>;
})}
</TableCell>
<TableCell align="left">
{employeeList.map((val, key) => {
const day = new Date(val.employeeStartDay).toLocaleDateString(
"pt-BR"
);
return <td>{day}</td>;
})}
</TableCell>
<TableCell align="left">
<p>-</p>
</TableCell>
<TableCell align="left">
<p>-</p>
</TableCell>
<TableCell align="left">
<p>-</p>
</TableCell>
</TableRow>
<TableRow>
<TableCell style={{ paddingBottom: 0, paddingTop: 0 }} colSpan={6}>
<Collapse in={open} timeout="auto" unmountOnExit>
<Box margin={1}>
<Typography variant="h6" gutterBottom component="div">
History
</Typography>
<Table size="small" aria-label="purchases">
<TableHead>
<TableRow>
<TableCell>From</TableCell>
<TableCell>To</TableCell>
<TableCell align="left">Days</TableCell>
<TableCell align="left">Paid</TableCell>
</TableRow>
</TableHead>
<TableBody>
{/* {row.history.map(() => (
<TableRow>
<TableCell component="th" scope="row"></TableCell>
<TableCell></TableCell>
<TableCell align="left"></TableCell>
<TableCell align="left"></TableCell>
</TableRow>
))} */}
</TableBody>
</Table>
</Box>
</Collapse>
</TableCell>
</TableRow>
</React.Fragment>
);
};
Row.propTypes = {
row: PropTypes.shape({
name: PropTypes.string,
startDate: PropTypes.string,
shift: PropTypes.string,
daysReceived: PropTypes.number,
daysUsed: PropTypes.number,
daysLeft: PropTypes.number,
history: PropTypes.arrayOf(
PropTypes.shape({
amount: PropTypes.number,
customerId: PropTypes.string,
date: PropTypes.string,
})
),
}),
};
return (
<div>
<TableContainer component={Paper}>
<Table aria-label="collapsible table">
<TableHead>
<TableRow>
<TableCell />
<TableCell>Name</TableCell>
<TableCell align="left">Employment Date</TableCell>
<TableCell align="left">Days received</TableCell>
<TableCell align="left">Days used</TableCell>
<TableCell align="left">Days left</TableCell>
</TableRow>
</TableHead>
<TableBody>
{employeeList.map((val, key) => (
<Row />
))}
</TableBody>
</Table>
</TableContainer>
</div>
);
}
Well, you are not giving the data to each row in the map call where you iterate over the employees. And then, instead you iterate of the whole thing again in each cell..
This should work:
const Row = ({val}) => {
const [open, setOpen] = React.useState(false);
const classes = useRowStyles();
return (
<React.Fragment>
<TableRow className={classes.root}>
<TableCell>
<IconButton
aria-label="expand row"
size="small"
onClick={() => setOpen(!open)}
>
{open ? <KeyboardArrowUpIcon /> : <KeyboardArrowDownIcon />}
</IconButton>
</TableCell>
<TableCell component="th" scope="row">
{val.employeeName}
</TableCell>
<TableCell align="left">
{(new Date(val.employeeStartDay)).toLocaleDateString("pt-BR")}
</TableCell>
<TableCell align="left">
<p>-</p>
</TableCell>
<TableCell align="left">
<p>-</p>
</TableCell>
<TableCell align="left">
<p>-</p>
</TableCell>
</TableRow>
<TableRow>
<TableCell style={{ paddingBottom: 0, paddingTop: 0 }} colSpan={6}>
<Collapse in={open} timeout="auto" unmountOnExit>
<Box margin={1}>
<Typography variant="h6" gutterBottom component="div">
History
</Typography>
<Table size="small" aria-label="purchases">
<TableHead>
<TableRow>
<TableCell>From</TableCell>
<TableCell>To</TableCell>
<TableCell align="left">Days</TableCell>
<TableCell align="left">Paid</TableCell>
</TableRow>
</TableHead>
<TableBody>
{/* {row.history.map(() => (
<TableRow>
<TableCell component="th" scope="row"></TableCell>
<TableCell></TableCell>
<TableCell align="left"></TableCell>
<TableCell align="left"></TableCell>
</TableRow>
))} */}
</TableBody>
</Table>
</Box>
</Collapse>
</TableCell>
</TableRow>
</React.Fragment>
);
};
Row.propTypes = {
row: PropTypes.shape({
name: PropTypes.string,
startDate: PropTypes.string,
shift: PropTypes.string,
daysReceived: PropTypes.number,
daysUsed: PropTypes.number,
daysLeft: PropTypes.number,
history: PropTypes.arrayOf(
PropTypes.shape({
amount: PropTypes.number,
customerId: PropTypes.string,
date: PropTypes.string,
})
),
}),
};
return (
<div>
<TableContainer component={Paper}>
<Table aria-label="collapsible table">
<TableHead>
<TableRow>
<TableCell />
<TableCell>Name</TableCell>
<TableCell align="left">Employment Date</TableCell>
<TableCell align="left">Days received</TableCell>
<TableCell align="left">Days used</TableCell>
<TableCell align="left">Days left</TableCell>
</TableRow>
</TableHead>
<TableBody>
{employeeList.map((val, key) => <Row val={val} key={key}/>)}
</TableBody>
</Table>
</TableContainer>
</div>
);
The structure you should be using should look something like this:
function Row(props) {
// you can access the employee object as `props.employee`
...
}
...
{employeeList.map((val, key) => <Row key={key} employee={val} />}
Each time you call the row function, it gives you a new row. For it to know what data should be in that row, you should be passing that data as a prop, instead of using the state. The flow of data would therefore be that the render method has a list of employees, and it calls the row builder function once with each of them, which gives back a list of rows to render.

display an full-width row in material-ui table react

I want to display some data in a table this is my JSX code:
const StudentsTable = (props) => {
const classes = useStyles();
return (
<TableContainer component={Paper}>
<Table className={classes.table} aria-label="simple table">
<TableHead>
<TableRow>
<TableCell>NR.</TableCell>
<TableCell align="right">NUME</TableCell>
<TableCell align="right">E-MAIL</TableCell>
<TableCell align="right">NR.TELEFON</TableCell>
<TableCell align="right">CLASA</TableCell>
<TableCell align="right">ACTIUNI</TableCell>
</TableRow>
</TableHead>
<TableBody>
{props.students.length > 0 ? (
props.students.map((student, i) => (
<TableRow key={student.studentName}>
<TableCell component="th" scope="row">
{i + 1}
</TableCell>
<TableCell align="right">{student.studentName}</TableCell>
<TableCell align="right">{student.studentEmail}</TableCell>
<TableCell align="right">{student.studentPhone}</TableCell>
<TableCell align="right">{student.clasa}</TableCell>
<TableCell align="center" className={classes.actionsCell}>
<BootstrapButton variant="primary" size="sm">
EDITARE
</BootstrapButton>
<BootstrapButton
variant="danger"
size="sm"
onClick={() => props.deleteStudent(student.studentName)}
>
STERGERE
</BootstrapButton>
</TableCell>
</TableRow>
))
) : (
<Typography variant="h5">
NU EXISTA ELEVI ADAUGATI.{"\n"} PUTETI ADAUGA APASAND PE BUTONUL
"ADAUGA ELEVI"
</Typography>
)}
</TableBody>
</Table>
</TableContainer>
);
};
when the props.students it's an empty array I want to return a single full-width row with this message: NU EXISTA ELEVI ADAUGATI.{"\n"} PUTETI ADAUGA APASAND PE BUTONUL "ADAUGA ELEVI" but in my app, the table looks something like this:
how to fix it?
In the place where you want to render a full row
use
<TableRow><TableCell colSpan={6}>"your message"</TableCell></TableRow>

How to merge React TableCells inside a map function?

So I am trying to create a table with material-ui where rows of w1 and w2 are merged vertically, but I can't seem to find a solution. Using rowSpan when hardcoding table manually works just fine, but when I use it inside map function it creates 4 columns with merged rows of the same element. I need to map data because there is going to be lots of rows in that table and hardcoding all rows is not reasonable.
Any type of suggestion to resolve this?
<TableBody>
{data.data.map((row, i) => (
<TableRow key={row.i}>
<TableCell className={classes.fontEditable} component="th" scope="row">
{row.x1}
</TableCell>
<TableCell className={classes.fontEditable} align="right">
{row.x2}
</TableCell>
<TableCell rowSpan={4} className={classes.fontEditable} align="right">
{row.w1}
</TableCell>
<TableCell rowSpan={4} className={classes.fontEditable} align="right">
{row.w2}
</TableCell>
<TableCell className={classes.font} align="right">
{row.t}
</TableCell>
</TableRow>
))}
</TableBody>
Expected outcome
Actual outcome
problem:
it creates the w1 and w2 cell in each row because of the map function
solution:
you can do an if condition for the w1 and w2 print for the first only as the following
<TableBody>
{data.data.map((row, i) => (
<TableRow key={row.i}>
<TableCell className={classes.fontEditable} component="th" scope="row">
{row.x1}
</TableCell>
<TableCell className={classes.fontEditable} align="right">
{row.x2}
</TableCell>
{i === 0?
<TableCell rowSpan={4} className={classes.fontEditable} align="right">
{row.w1}
</TableCell>
<TableCell rowSpan={4} className={classes.fontEditable} align="right">
{row.w2}
</TableCell>
:null}
<TableCell className={classes.font} align="right">
{row.t}
</TableCell>
</TableRow>
))}

Categories