Customize TableRow with Material UI component - reactjs

I'm using Material UI table example and trying to customize the rows to have my own component to replace the default row.I want to have some margin between the rows and a shadow (using elevation prop of Paper element). This is what I achieved so far:
import React, { useState } from 'react'
import Paper from '#material-ui/core/Paper';
import Table from '#material-ui/core/Table';
import TableBody from '#material-ui/core/TableBody';
import TableCell from '#material-ui/core/TableCell';
import TableContainer from '#material-ui/core/TableContainer';
import TableHead from '#material-ui/core/TableHead';
import TableRow from '#material-ui/core/TableRow';
const MyPaper = (item) => {
return (
<Paper
elevation={6}>
{item}
</Paper>
);
};
const List = () => {
const items = ['a', 'b'];
return (
<div style={{ maxWidth: "100%" }}>
<TableContainer>
<Table aria-label="simple table">
<TableHead>
<TableRow>
<TableCell>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>
<TableBody>
{items.map(item => (
<TableRow key={item} component={() => MyPaper(item)}>
<TableCell>{item}</TableCell>
<TableCell>{item}</TableCell>
<TableCell>{item}</TableCell>
<TableCell>{item}</TableCell>
<TableCell>{item}</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
</div>
)
}
export default List
but the result is being applied only in the first column. How do I fix this to have my custom row to occupy the entire table space?
Thanks in advance

You can do it easily with withstyles property of Material-UI, you can arrange Paper or other MUI components to give them classes and arrange them in styles variable:
import React, { useState } from 'react'
import Paper from '#material-ui/core/Paper';
import Table from '#material-ui/core/Table';
import TableBody from '#material-ui/core/TableBody';
import TableCell from '#material-ui/core/TableCell';
import TableContainer from '#material-ui/core/TableContainer';
import TableHead from '#material-ui/core/TableHead';
import TableRow from '#material-ui/core/TableRow';
import { WithStyles } from '#material-ui/core'
const styles = theme => ({
...theme,
Row: {
margin: 10
}
})
const List = () => {
const items = ['a', 'b'];
const {classes} = this.props
return (
<div style={{ maxWidth: "100%" }}>
<TableContainer>
<Table aria-label="simple table">
<TableHead>
<TableRow>
<TableCell>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>
<TableBody>
{items.map(item => (
<TableRow key={item} className={classes.Row}>
<TableCell>{item}</TableCell>
<TableCell>{item}</TableCell>
<TableCell>{item}</TableCell>
<TableCell>{item}</TableCell>
<TableCell>{item}</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
</div>
)
}
export default withStyles(styles)(List)

Related

How can I Show Only my Videos in Django-Rest-Framework?

I'm using Django and React to create YouTube clone.
And I have an admin panel where user can delete and edit his videos.
But the problem is that it showing my videos and other users videos.
How can make that the admin panel will show only my videos?
views.py Api Views
class AdminVideoDetail(generics.RetrieveAPIView):
permission_classes = [IsAuthenticated]
quesryset = Video.objects.all()
serializer_class = VideoSerializer
videos.js Videos in the admin panel
import React from 'react';
import { makeStyles } from '#material-ui/core/styles';
import Container from '#material-ui/core/Container';
import Link from '#material-ui/core/Link';
import Paper from '#material-ui/core/Paper';
import Table from '#material-ui/core/Table';
import TableBody from '#material-ui/core/TableBody';
import TableCell from '#material-ui/core/TableCell';
import TableContainer from '#material-ui/core/TableContainer';
import TableHead from '#material-ui/core/TableHead';
import TableRow from '#material-ui/core/TableRow';
import DeleteForeverIcon from '#material-ui/icons/DeleteForever';
import EditIcon from '#material-ui/icons/Edit';
import Button from '#material-ui/core/Button';
const useStyles = makeStyles((theme) => ({
cardMedia: {
paddingTop: '56.25%', // 16:9
},
link: {
margin: theme.spacing(1, 1.5),
},
cardHeader: {
backgroundColor:
theme.palette.type === 'light'
? theme.palette.grey[200]
: theme.palette.grey[700],
},
videoTitle: {
fontSize: '16px',
textAlign: 'left',
},
videoText: {
display: 'flex',
justifyContent: 'left',
alignItems: 'baseline',
fontSize: '12px',
textAlign: 'left',
marginBottom: theme.spacing(2),
},
}));
const Videos = (props) => {
const { videos } = props;
const classes = useStyles();
if (!videos || videos.length === 0) return <Button href={'/admin/create'} variant="contained" color="primary">New Video</Button>;
return (
<React.Fragment>
<Container maxWidth="md" component="main">
<Paper className={classes.root}>
<TableContainer className={classes.container}>
<Table stickyHeader aria-label="sticky table">
<TableHead>
<TableRow>
<TableCell>Id</TableCell>
<TableCell align="left">Title</TableCell>
<TableCell align="left">Action</TableCell>
</TableRow>
</TableHead>
<TableBody>
{videos.map((video) => {
return (
<TableRow>
<TableCell component="th" scope="row">
{video.id}
</TableCell>
<TableCell align="left">
<Link
color="textPrimary"
href={'/video/' + video.id}
className={classes.link}
>
{video.title}
</Link>
</TableCell>
<TableCell align="left">
<Link
color="textPrimary"
href={'/admin/edit/' + video.id}
className={classes.link}
>
<EditIcon></EditIcon>
</Link>
<Link
color="textPrimary"
href={'/admin/delete/' + video.id}
className={classes.link}
>
<DeleteForeverIcon></DeleteForeverIcon>
</Link>
</TableCell>
</TableRow>
);
})}
<TableRow>
<TableCell colSpan={4} align="right">
<Button
href={'/admin/create'}
variant="contained"
color="primary"
>
New Video
</Button>
</TableCell>
</TableRow>
</TableBody>
</Table>
</TableContainer>
</Paper>
</Container>
</React.Fragment>
);
};
export default Videos;
If you want to look at the whole project, here is github: https://github.com/PHILLyaHI/diplom-work
Create a python module named permissions.py
add these line of code
from rest_framework import permissions
class IsOwnerOrReadOnly(permissions.BasePermission):
"""
"""
def has_object_permission(self, request, view, obj):
# I check if the request is of type GET or OPTIONS
#I return true, that the use is able to access on this views
if request.method in permissions.SAFE_METHODS:
return True
return obj.owner == request.user
"""
Instance must have an attribute named `owner` or you can change owner with the name of your models fields `user = models.ForeignKey(UserModel, on_delete=models.casscade).
"""
After, go in your views.py module, add
class AdminVideoDetail(generics.RetrieveAPIView):
permission_classes = [IsAuthenticated, IsOwnerOrReadOnly]
quesryset = Video.objects.all()
serializer_class = VideoSerializer
Only videos of owner will be fetch

How to get the value of clicked cell in React Material Table?

I am trying to get the corresponding value of cell in React Material UI Table Component.
I was looking for already predefined component api properties but couldn't find anything appropriate.
Working with Material UI DataGrid component, I achieved that, getting the selected row via onSelectionModelChange thanks to this answer.
But in this case, Table doesn't have any checkboxes and I need to retrieve the data by clicking.
Here is the codesandbox link and the example code:
import * as React from "react";
import Table from "#mui/material/Table";
import TableBody from "#mui/material/TableBody";
import TableCell from "#mui/material/TableCell";
import TableContainer from "#mui/material/TableContainer";
import TableHead from "#mui/material/TableHead";
import TableRow from "#mui/material/TableRow";
import Paper from "#mui/material/Paper";
export default function BasicTable({ users }: any) {
return (
<TableContainer component={Paper}>
<Table sx={{ minWidth: 650 }} aria-label="simple table">
<TableHead>
<TableRow>
<TableCell>userId</TableCell>
<TableCell align="right">id</TableCell>
<TableCell align="right">Title</TableCell>
</TableRow>
</TableHead>
<TableBody>
{users &&
users.map((user: any) => (
<TableRow
key={users.id}
sx={{ "&:last-child td, &:last-child th": { border: 0 } }}
>
<TableCell align="right">{user.userId}</TableCell>
<TableCell align="right">{user.id}</TableCell>
<TableCell align="right">{user.title}</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
);
}
Any help will be appreciated.
You can create an onClick function on the cells that you want this behavior to happen. Assuming that you want this on user.title cells and using console.log as example:
<TableCell align="right" onClick={({target}) => console.log(target.textContent)}>{user.title}</TableCell>
Since you are mapping over your data, you can simply use the desired data from the map:
{users &&
users.map((user: any) => (
<TableRow
key={user.id}
onClick={() => console.log(user.id)} // set desired state here
>
<TableCell align="right">{user.userId}</TableCell>
<TableCell align="right">{user.id}</TableCell>
<TableCell align="right">{user.title}</TableCell>
</TableRow>
))}

How to display state object elements in another component?

i'm trying to use a table from MaterialUI and populate it with financial data (using promise API). I have three components:
Gl.js
myTable
index.js
I want to use the state object in the Gl.js component and populate the table in myTable.js but not sure how to. Please ask for more details if necessary, I must complete this project.
GL.js
import React, { Component, createContext, Provider } from 'react';
import ReactDOM from 'react-dom';
import axios from "axios";
import CollapsibleTable from './myTable';
export const CTX = React.createContext();
class Gl extends React.Component {
_isMounted = false;
constructor(props) {
super(props)
this.state = {
applBs: []
}
}
getData() {
const axios = require("axios");
axios({
"method": "GET",
"url": "https://fmpcloud.p.rapidapi.com/balance-sheet-statement/AAPL",
"headers": {
"content-type": "application/octet-stream",
"x-rapidapi-host": "fmpcloud.p.rapidapi.com",
"x-rapidapi-key": "4560d76562msh36c4de0a03c6e54p1bf4a2jsne2d882693304",
"useQueryString": true
}, "params": {
"period": "annual",
"apikey": "demo"
}
})
.then(response => {
if (this._isMounted) {
this.setState({ applBs: response.data[0] })
}
})
.catch(error => {
console.log(error)
})
}
componentDidMount() {
this._isMounted = true;
this.getData();
}
componentWillUnamount() {
this._isMounted = false;
}
render() {
return (
<div>
<CollapsibleTable callData={this.state.applBs} />
<CTX.Provider value={ this.state.applBs }>
{this.props.children}
</CTX.Provider>
</div>
)
}
}
ReactDOM.render(<Gl />, document.getElementById("root"))
export default Gl
myTable.js
import React, { Component, Consumer } from 'react';
import ReactDOM from "react-dom"
import PropTypes from 'prop-types';
import { makeStyles } from '#material-ui/core/styles';
import Box from '#material-ui/core/Box';
import Collapse from '#material-ui/core/Collapse';
import IconButton from '#material-ui/core/IconButton';
import Table from '#material-ui/core/Table';
import TableBody from '#material-ui/core/TableBody';
import TableCell from '#material-ui/core/TableCell';
import TableContainer from '#material-ui/core/TableContainer';
import TableHead from '#material-ui/core/TableHead';
import TableRow from '#material-ui/core/TableRow';
import Typography from '#material-ui/core/Typography';
import Paper from '#material-ui/core/Paper';
import KeyboardArrowDownIcon from '#material-ui/icons/KeyboardArrowDown';
import KeyboardArrowUpIcon from '#material-ui/icons/KeyboardArrowUp';
import CTX from "./GL.js"
const useRowStyles = makeStyles({
root: {
'& > *': {
borderBottom: 'unset',
},
},
});
function createData(name, calories, fat, carbs, protein, price) {
return {
name,
calories,
fat,
carbs,
protein,
price,
history: [
{ lineItem: 'Pop', date: '2020-01-05', customerId: '11091700', amount: 3 },
{ lineItem: 'Pop', date: '2020-01-02', customerId: 'Anonymous', amount: 1 },
],
};
}
function Row(props) {
const { row } = props;
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">
{row.name}
</TableCell>
<TableCell align="right">{row.calories}</TableCell>
<TableCell align="right">{row.fat}</TableCell>
<TableCell align="right">{row.carbs}</TableCell>
<TableCell align="right">{row.protein}</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>
Line Item
</TableCell>
<TableCell>
Google
</TableCell>
<TableCell>
Customer
</TableCell>
<TableCell align="right">
Amount
</TableCell>
<TableCell align="right">
Total price ($)
</TableCell>
</TableRow>
</TableHead>
<TableBody>
{row.history.map((historyRow) => (
<TableRow key={historyRow.date}>
<TableCell component="th" scope="row">
{historyRow.date}
</TableCell>
<TableCell>{historyRow.customerId}</TableCell>
<TableCell align="right">{historyRow.amount}</TableCell>
<TableCell align="right">
{Math.round(historyRow.amount * row.price * 100) / 100}
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</Box>
</Collapse>
</TableCell>
</TableRow>
</React.Fragment>
);
}
Row.propTypes = {
row: PropTypes.shape({
calories: PropTypes.number.isRequired,
carbs: PropTypes.number.isRequired,
fat: PropTypes.number.isRequired,
history: PropTypes.arrayOf(
PropTypes.shape({
amount: PropTypes.number.isRequired,
customerId: PropTypes.string.isRequired,
date: PropTypes.string.isRequired,
}),
).isRequired,
name: PropTypes.string.isRequired,
price: PropTypes.number.isRequired,
protein: PropTypes.number.isRequired,
}).isRequired,
};
const rows = [
createData('Frozen yoghurt', 159, 6.0, 24, 4.0, 3.99),
createData('Ice cream sandwich', 237, 9.0, 37, 4.3, 4.99),
createData('Eclair', 262, 16.0, 24, 6.0, 3.79),
createData('Cupcake', 305, 3.7, 67, 4.3, 2.5),
createData('Gingerbread', 356, 16.0, 49, 3.9, 1.5),
];
export default function CollapsibleTable() {
return (
<TableContainer component={Paper}>
<Table aria-label="collapsible table">
<TableHead>
<TableRow>
<TableCell />
<TableCell>
Apple.Inc
</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>
<TableBody>
{rows.map((row) => (
<Row key={row.name} row={row} />
))}
</TableBody>
</Table>
</TableContainer>
);
}
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import Gl from './GL';
import CollapsibleTable from './myTable';
ReactDOM.render(
<React.StrictMode>
<Gl >
<CollapsibleTable />
</Gl>
</React.StrictMode>,
document.getElementById('root'));
ok then this must be the issue be clear with class and functional component this keyword can be used only in class component!!
check this link for further reference link
in your case have a console in
<TableContainer component={Paper}>
{console.log('callData', props.callData)}
<Table aria-label="collapsible table">
you will get the value of callData use that to display in table

I am looking for how to draw a vertical line on a table component of material ui

Is there a good way to do it?
I am looking for the way...
However, I can't reach reliable information.
https://material-ui.com/ja/components/tables/
make a div above the material-ui table with a unique className, then in css make following changes
eg:
<div className="uniqueName">
<Material UI Table/> //material ui table here
</div>
in Css
.uniqueName th,
td {
border: 1px solid rgba(224, 224, 224, 1);
}
This is not conventional, but it does the trick. I achieved this by adding Borders around each <TableCell> component. You can also wrap <TableRow> or <TableHead> components. Given below is an example of how to add a Right Border on a cell. If you want the middle verticle line, then add a Right Border on all the <TableCell> of the first column.
const styles = theme => {
tableRightBorder : { borderWidth: 0, borderWidth: 1, borderColor: 'red',borderStyle: 'solid'} // or borderTop: '1px solid red'
}
...
class TableComponent ...
{ classes } = this.props;
<Table >
<TableHead>
<TableRow >
<TableCell className={classes.tableRightBorder}>Column 1</TableCell>
<TableCell>Column 2</TableCell>
</TableRow>
</TableHead>
<TableBody>
<TableRow>
<TableCell className={classes.tableRightBorder}>Cell 1</TableCell>
<TableCell>Cell 2</TableCell>
</TableRow>
</TableBody>
</Table>
export default withStyles(styles)(TableComponent)
This will look like this...
For a complete working component of the above image, try this table
import React from 'react';
import PropTypes from 'prop-types';
import { makeStyles } from '#material-ui/styles';
import {
Table,
TableBody,
TableCell,
TableHead,
TableRow,
} from '#material-ui/core';
import { connect } from 'react-redux';
const useStyles = makeStyles(theme => ({
root: {},
tableRightBorder: {
borderWidth: 0,
borderRightWidth: 1,
borderColor: 'black',
borderStyle: 'solid',
},
}));
const DataTable = props => {
const classes = useStyles();
return (
<Table>
<TableHead>
<TableRow>
<TableCell className={classes.tableRightBorder}>
Column 1
</TableCell>
<TableCell>Column 2</TableCell>
</TableRow>
</TableHead>
<TableBody>
<TableRow>
<TableCell className={classes.tableRightBorder}>
Cell 1
</TableCell>
<TableCell>Cell 2</TableCell>
</TableRow>
</TableBody>
</Table>
);
};
DataTable.propTypes = {
className: PropTypes.string,
};
function mapStateToProps() {}
export default connect(mapStateToProps, {})(DataTable);
I like to do it like this; wrap the component with styling and use it as a new component:
const CellWithRightBorder = withStyles((theme: Theme) =>
createStyles({
root: {
borderRightWidth: 1,
borderRightColor: theme.palette.grey[300],
borderRightStyle: "solid",
},
})
)(TableCell);
const MyTable = () => {
<TableContainer component={Paper}>
<Table size="small" aria-label="a dense table">
<TableHead>
<TableRow>
<CellWithRightBorder>Bla</CellWithRightBorder>
</TableRow>
</TableHead>
</Table>
</TableContainer>
}

Passing Arguments to Event Handlers

I'd be grateful if you could help me with my problem.
I've written a component to demonstrate the information of an array which includes both index.js and TableData.js files.Transferring the information of array from index.js to TableData in order to demonstrating them.
I passed the arguments to event handler correctly but I get an error. What's the problem with my code? In which part have I made a mistake?
App.js
import React, {Component, Fragment} from 'react';
import {TableData} from './Layouts'
class App extends Component {
state = {
productList: [
{id: 11, name: 'CD', price: '2000', describe: 'Educational'},
{id: 24, name: 'Pen', price: '3500', describe: 'Design'},
{id: 83, name: 'Pencil', price: '2500', describe: 'Design'}
],
};
handleDeleteByIndex = index => {
const product = this.state.productList;
product.splice(index, 1);
this.setState({productList: product});
};
render() {
const {productList} = this.state;
return (
<Fragment>
<TableData rows={productList} onDeleteRow={this.handleDeleteByIndex}/>
</Fragment>
);
}
}
export default App
TableData.js
import React from 'react';
import {makeStyles} from '#material-ui/core/styles';
import {
Table,
TableBody,
TableCell,
TableHead,
TableRow,
Paper
} from '#material-ui/core';
//****** Style CSS ******
const useStyles = makeStyles({
root: {
width: '100%',
overflowX: 'auto'
},
table: {
minWidth: 650
}
});
const test = 'right';
const TableData= (props) => {
const classes = useStyles();
return (
<Paper className={classes.root}>
<Table className={classes.table} aria-label="simple table">
<TableHead>
<TableRow>
<TableCell>Name Product</TableCell>
<TableCell align="right">Price</TableCell>
<TableCell align="right">Describe</TableCell>
</TableRow>
</TableHead>
<TableBody>
{props.rows.map((item, index) => (
<TableRow key={item.id}>
<TableCell component="th" scope="row">
{item.name}
</TableCell>
<TableCell align={test} data={item.name}>{item.price}</TableCell>
<TableCell align="right">{item.describe}</TableCell>
<TableCell align="right">
<button onClick={() => props.handleDeleteByIndex(index)}>
DEL
</button>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</Paper>
);
};
export default TableData
You are calling a function that does not exist. The passed down function in props is called onDeleteRow, not handleDeleteByIndex.
Just change it into:
onClick={() => props.onDeleteRow(index)}

Resources