How to change page in mateiral ui table based on search? - reactjs

Like the title says I need to change the page based on search value. What do I mean by this, let's say that the name Test is on th page 2 of my table, but not on page 1. How do I then change the page automatically?
Here is my TableComponent.js:
import React, { useState } 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 useFetch from "./custom_hooks/useFetch";
import TableFooter from "#mui/material/TableFooter";
import TablePagination from "#mui/material/TablePagination";
import IconButton from "#mui/material/IconButton";
import Box from "#mui/material/Box";
import { MdKeyboardArrowRight, MdKeyboardArrowLeft } from "react-icons/md";
import styled from "styled-components";
const TableH = styled(TableHead)`
height: 3.5rem;
`;
const TableB = styled(TableBody)`
height: 3.375rem;
`;
const RoleButton = styled.button`
color: #c80539;
outline: none;
border: none;
background: none;
cursor: pointer;
font-size: 14px;
font-weight: normal;
font-stretch: normal;
font-style: normal;
line-height: 1.43;
letter-spacing: normal;
`;
function TablePaginationActions(props) {
const { page, onPageChange } = props;
const handleBackButtonClick = (event) => {
onPageChange(event, page);
};
const handleNextButtonClick = (event) => {
onPageChange(event, page + 2);
};
return (
<Box sx={{ flexShrink: 0, ml: 2.5 }}>
<IconButton
onClick={handleBackButtonClick}
disabled={page === 0}
aria-label="previous page"
>
<MdKeyboardArrowLeft color="#707070" />
</IconButton>
<IconButton onClick={handleNextButtonClick} aria-label="next page">
<MdKeyboardArrowRight color="#707070" />
</IconButton>
</Box>
);
}
const TableComponent = ({ url, cellNames, value }) => {
const [page, setPage] = useState(1);
const [rowsPerPage, setRowsPerPage] = useState(5);
const [roles, setRoles] = useState("Admin");
const { data, error } = useFetch(`${url}${page}`);
if (!data) {
return <h1> LOADING...</h1>;
}
if (error) {
console.log(error);
}
const handleChangePage = (event, newPage) => {
setPage(newPage);
};
const handleChangeRowsPerPage = (event) => {
setRowsPerPage(parseInt(event.target.value, 10));
};
// currently this is not functional as it is supposed to be, right now when you click on a button it is going to change role for everyone
const handleRoleChange = () => {
if (roles === "Admin") {
setRoles("User");
} else {
setRoles("Admin");
}
};
return (
<TableContainer
style={{
height: 385,
border: "1px solid #e2e2e3",
borderRadius: 5,
}}
data-testid="table-container"
>
<Table stickyHeader>
<TableH>
<TableRow>
{cellNames.map((names, index) => {
return (
<TableCell
style={{
fontWeight: "bold",
fontSize: 14,
paddingRight: names.paddingRight,
paddingLeft: names.paddingLeft,
}}
align={names.align}
key={index}
>
{names.name}
</TableCell>
);
})}
</TableRow>
</TableH>
<TableB>
{data.data
.filter((val) => {
const notFound = !val.name
.toLowerCase()
.includes(value.toLowerCase());
if (value === "") {
return val;
} else if (val.name.toLowerCase().includes(value.toLowerCase())) {
return val;
} else if (notFound) {
// WHAT TO DO HERE ????
}
})
.slice(0, rowsPerPage)
.map((apiData, index) => {
return (
<TableRow key={index}>
<TableCell align="left" style={{ paddingLeft: 40 }}>
{apiData.name}
</TableCell>
<TableCell align="left">{apiData.email}</TableCell>
<TableCell align="left">{apiData.status}</TableCell>
<TableCell align="left">{roles}</TableCell>
<TableCell align="right" style={{ paddingRight: 40 }}>
<RoleButton onClick={handleRoleChange}>
{roles === "Admin" ? "Set as User" : "Set as Admin"}
</RoleButton>
</TableCell>
</TableRow>
);
})}
</TableB>
<TableFooter>
<TableRow>
<TablePagination
rowsPerPageOptions={[5, 10]}
colSpan={6}
style={{
borderBottom: "none",
height: 50,
color: "#707070",
}}
count={data.meta.pagination.total}
rowsPerPage={rowsPerPage}
page={page - 1}
SelectProps={{
inputProps: {
"aria-label": "rows per page",
},
native: true,
}}
onPageChange={handleChangePage}
onRowsPerPageChange={handleChangeRowsPerPage}
ActionsComponent={TablePaginationActions}
/>
</TableRow>
</TableFooter>
</Table>
</TableContainer>
);
};
export default TableComponent;
If anyone know how to do this, I would greatly appreciate that. As I only recently started using Material UI, this seems complicated for me. I assume that somehow I need to change page based on condition that the value is not found on current page, but how do I implement that?

Related

MUI table Row collapse squashed into one cell when expanded and alignment error

Trying to use MUI table with Collapse to expand/collapse rows. However when using collapse, the the expanded rows are squashed into one cell. How can I align the expanded cells to the parent table cells in a material-ui table?
what i tried is on this link https://codesandbox.io/s/affectionate-leaf-lhb47z
CODE
import React, { useState } from "react";
import { makeStyles } from "#material-ui/core/styles";
import Grid from "#material-ui/core/Grid";
import Card from "#material-ui/core/Card";
import CardHeader from "#material-ui/core/CardHeader";
import Table from "#material-ui/core/Table";
import TableBody from "#material-ui/core/TableBody";
import TableCell from "#material-ui/core/TableCell";
import TableHead from "#material-ui/core/TableHead";
import TableRow from "#material-ui/core/TableRow";
import Paper from "#material-ui/core/Paper";
import TableContainer from "#material-ui/core/TableContainer";
import IconButton from "#material-ui/core/IconButton";
import KeyboardArrowDownIcon from "#material-ui/icons/KeyboardArrowDown";
import KeyboardArrowUpIcon from "#material-ui/icons/KeyboardArrowUp";
const useStyles = makeStyles((theme) => ({
header: {
backgroundColor: "white",
color: "#546e7a",
justifyContent: "left",
padding: "10px 0px",
fontWeight: "bold"
},
content: {
padding: 0
},
status: {
marginRight: "5px"
},
actions: {
justifyContent: "flex-end"
},
summaryTable: {
width: "auto",
marginBottom: "10px",
pointerEvents: "none"
},
noBorder: {
border: "none"
},
denseCell: {
padding: "5px"
},
formControl: {
margin: theme.spacing(1),
minWidth: 120
},
inputGroup: {
marginBottom: theme.spacing(1)
}
}));
const data1 = [
{
amount: 400.0,
dr_cr: "dr",
ledgerName: "Furniture"
},
{
amount: 10,
dr_cr: "dr",
ledgerName: "chocolate"
},
{
amount: 100.0,
dr_cr: "dr",
ledgerName: "goods purchase"
}
];
const data = [
{
amount: 510.0,
dr_cr: "dr",
ledgerName: "Assets"
},
{
amount: 5,
dr_cr: "cr",
ledgerName: "Liability"
}
];
const ExpandableTableRow = ({ children, expandComponent, ...otherProps }) => {
const [isExpanded, setIsExpanded] = React.useState(false);
return (
<>
<TableRow {...otherProps}>
<TableCell padding="checkbox">
<IconButton onClick={() => setIsExpanded(!isExpanded)}>
{isExpanded ? <KeyboardArrowUpIcon /> : <KeyboardArrowDownIcon />}
</IconButton>
</TableCell>
{children}
</TableRow>
{isExpanded && (
<TableRow>
<TableCell/>
{expandComponent}
</TableRow>
)}
</>
);
};
export default function App() {
const classes = useStyles();
const [records, setRecords] = useState(data || []);
const [records1, setRecords1] = useState(data1 || []);
return (
<div className="App">
<Grid item lg={12} md={12} xs={12}>
<Card>
<CardHeader
className={classes.header}
title={"Report"}
classes={{
title: classes.header
}}
/>
<Table stickyHeader>
<TableHead>
<TableRow>
<TableCell />
<TableCell>LedgerName</TableCell>
<TableCell>Debit</TableCell>
<TableCell>Credit</TableCell>
</TableRow>
</TableHead>
<TableBody>
{records.map((item) => (
<ExpandableTableRow
key={item.ledgerName}
expandComponent={
<Table>
<TableBody>
{records1.map((i) => (
<TableRow>
<TableCell>{i.ledgerName}</TableCell>
<TableCell>
{i.dr_cr === "dr" ? Math.round(i.amount, 2) : 0}
</TableCell>
<TableCell>
{i.dr_cr === "cr" ? Math.round(i.amount, 2) : 0}
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
}
>
<TableCell>{item.ledgerName}</TableCell>
<TableCell>
{item.dr_cr === "dr" ? Math.round(item.amount, 2) : 0}
</TableCell>
<TableCell>
{item.dr_cr === "cr" ? Math.round(item.amount, 2) : 0}
</TableCell>
</ExpandableTableRow>
))}
</TableBody>
</Table>
</Card>
</Grid>
</div>
);
}

How to control material UI Accordian expansion / collapse by click on icon from another component?

Actually, i'm creating the table where i've to expand the Row by clicking the icon on another column! any help will be appreciated ! (i'm using material UI components like table, accordian)
Here's the Demo of my code on sandbox!
https://codesandbox.io/s/proud-resonance-iryir7?file=/src/App.js:73-74
My concern is when I click on message icon, email cell will be expanded!
import {
Accordion,
AccordionDetails,
AccordionSummary,
Box,
Grid,
TextField,
Typography
} from "#mui/material";
import React, { useEffect, useState } from "react";
import PictureAsPdfIcon from "#mui/icons-material/PictureAsPdf";
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 Collapse from "#mui/material/Collapse";
import TableHead from "#mui/material/TableHead";
import TableRow from "#mui/material/TableRow";
import Paper from "#mui/material/Paper";
import InfoOutlinedIcon from "#mui/icons-material/InfoOutlined";
import ChatBubbleOutlineOutlinedIcon from "#mui/icons-material/ChatBubbleOutlineOutlined";
import Modal from "#mui/material/Modal";
const Example = () => {
const [Data, setData] = useState([]);
const [open, setOpen] = React.useState(false);
const [expandedId, setExpandedId] = useState("0");
const handleOpen = () => setOpen(true);
const handleClose = () => setOpen(false);
function createData(
name,
id,
email
) {
return {
name,
id,
email
};
}
const modalstyle = {
position: "absolute",
top: "50%",
left: "50%",
transform: "translate(-50%, -50%)",
width: 400,
bgcolor: "background.paper",
border: "2px solid #000",
boxShadow: 24,
p: 4
};
useEffect(() => {
fetch("https://jsonplaceholder.typicode.com/users")
.then((res) => res.json())
.then((result) => setData(result));
});
const rows = [
Data.map((data) =>
createData(
data.name,
data.id,
data.email
)
)
];
return (
<div>
<div className="heading">
<Grid container>
<Grid item md={9} sm={9} xs={12}></Grid>
</Grid>
<div className="box">
<TableContainer component={Paper}>
<Table aria-label="simple table">
<TableHead
sx={{
"& .MuiTableCell-head": {
backgroundColor: "#000000",
color: "#ffffff",
height: "55px",
textAlign: "center",
fontSize: "14px"
}
}}
>
<TableRow>
<TableCell>name</TableCell>
<TableCell align="right">email</TableCell>
<TableCell></TableCell>
</TableRow>
</TableHead>
<TableBody>
{rows[0].map((row) => (
<TableRow
sx={{
"& td, & th": {
border: 1,
borderColor: "gray"
}
}}
key={row.id}
>
<TableCell component="th" scope="row">
<div className="codes" onClick={handleOpen}>
{`${row.name} ${row.id}`}
</div>
</TableCell>
<TableCell align="left">
<div className="msg-container">
<Accordion
elevation={0}
key={row.Id}
// onChange={handleChangeExpanded(`panel_${row.id}`)}
expanded = {expandedId === row.id}
>
<AccordionSummary
ariaControls={`${row.id}_panel1a-content`}
id={`${row.id}_panel1a-id`}
>
<div className="msg">{row.email}</div>
</AccordionSummary>
<AccordionDetails>
<TextField placeholder="Enter Here"></TextField>
</AccordionDetails>
</Accordion>
</div>
</TableCell>
<TableCell>
<div className="info-icon-container">
<div className="info-icon" onClick={handleOpen}>
<InfoOutlinedIcon />
</div>
<Modal
open={open}
onClose={handleClose}
aria-labelledby="modal-modal-title"
aria-describedby="modal-modal-description"
BackdropProps={{
style: {
background: "transparent"
}
}}
>
<Box sx={modalstyle}>
<Typography
id="modal-modal-title"
variant="h6"
component="h2"
>
Text in a modal
</Typography>
<Typography
id="modal-modal-description"
sx={{ mt: 2 }}
>
Duis mollis, est non commodo luctus, nisi erat
porttitor ligula.
</Typography>
</Box>
</Modal>
<div className="chatbubble-icon">
<ChatBubbleOutlineOutlinedIcon onClick={() => setExpandedId(prev => prev === row.id ? "0" : row.id)} />
</div>
</div>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
</div>
</div>
</div>
);
};
export default Example;
check this out.

Cannot read properties of undefined (reading 'value-domain') in React.Js

I am having a problem that I don't know where it cause. Please help me out.
I am developing a stock management platform, it allows users to CRUD products.
When Users are on the product page, they will see a table with edit and delete buttons in every record.
Whenever they click on the delete button, it will show a PopOver to confirm the delete action.
And the error happens when I click "Yes" in the PopOver Component
I am using Material-UI version 4.12.3,
Here is my parent component:
const useStyles = makeStyles((theme) => ({
modal: {
display: "flex",
alignItems: "center",
justifyContent: "center",
},
paper: {
backgroundColor: theme.palette.background.paper,
border: "2px solid #000",
boxShadow: theme.shadows[5],
padding: theme.spacing(2, 4, 3),
},
loading: {
display: "flex",
justifyContent: "center",
},
}));
const useRowStyles = makeStyles({
root: {
"& > *": {
borderBottom: "100%",
},
},
});
function createData(id, name, supplier, type, unit, quantity, cost, price, ingredients, action) {
return {
id,
name,
supplier,
type,
unit,
quantity,
cost,
price,
ingredients,
action,
};
}
function Row(props) {
const { row } = props;
const [open, setOpen] = React.useState(false);
const classes = useRowStyles();
const isCocktail = (type) => {
if (type === "Cocktail" || type === "Mocktail") {
return true;
} else {
return false;
}
};
return (
<React.Fragment>
<TableRow className={classes.root}>
<TableCell>
{isCocktail(row.type) ? (
<IconButton aria-label="expand row" size="small" onClick={() => setOpen(!open)}>
{open ? <KeyboardArrowUpIcon /> : <KeyboardArrowDownIcon />}
</IconButton>
) : null}
</TableCell>
<TableCell component="th" scope="row">
{row.id}
</TableCell>
<TableCell align="middle">{row.name}</TableCell>
<TableCell align="middle">{row.supplier}</TableCell>
<TableCell align="middle">{row.type}</TableCell>
<TableCell align="middle">{row.unit}</TableCell>
<TableCell align="middle">{row.quantity}</TableCell>
<TableCell align="middle">{row.cost}</TableCell>
<TableCell align="middle">{row.price}</TableCell>
<TableCell align="middle">{row.action}</TableCell>
</TableRow>
<TableRow></TableRow>
</React.Fragment>
);
}
function Ingredients({ controller }) {
const classes = useStyles();
const dispatch = useDispatch();
const loading = useSelector((state) => state.product.loading);
const listProducts = useSelector((state) => state?.product?.products?.products);
const role = useSelector((state) => state.auth.user.role);
const [open, setOpen] = React.useState(false);
const nonCocktailList = listProducts?.filter((e) => e.type !== "Cocktail");
const nonMocktailList = nonCocktailList?.filter((e) => e.type !== "Mocktail");
const nonFoodList = nonMocktailList?.filter((e) => e.type !== "Food");
const handleOpen = async (id) => {
await dispatch(productActions.getSingleProduct(id));
setOpen(true);
};
const handleClose = () => {
setOpen(false);
};
let vietNamD = Intl.NumberFormat("vi-VI");
let rows = nonFoodList?.map((product, index) => {
return createData(
index,
product?.name,
product?.supplier,
product?.unit,
`${product?.capacity + " " + product?.capacityUnit}`,
`${vietNamD.format(product?.cost)} đ`,
`${product?.quantity + " " + product?.unit}`,
<div className="actions">
<Button variant="contained" style={{ backgroundColor: "#2EC0FF", color: "white" }} onClick={() => handleOpen(product?._id)}>
<EditOutlinedIcon style={{ color: "white" }} />
</Button>
<PopOver id={product._id} role={role} controller={controller} />
</div>
);
});
useEffect(() => {
dispatch(supplierActions.getSuppliers());
}, [dispatch]);
return loading ? (
<div className={classes.loading}>
{" "}
<CircularProgress />
</div>
) : (
<div className="create-button">
<Modal
aria-labelledby="transition-modal-title"
aria-describedby="transition-modal-description"
className={classes.modal}
open={open}
onClose={handleClose}
closeAfterTransition
BackdropComponent={Backdrop}
BackdropProps={{
timeout: 500,
}}
>
<Fade in={open}>
<CreateUpdateIngredient handleClose={handleClose} controller={controller} />
</Fade>
</Modal>
<IngredientModal controller={controller} />
<TableContainer component={Paper}>
<Table aria-label="collapsible table">
<TableHead style={{ backgroundColor: "black", width: "100%" }}>
<TableRow>
<TableCell />
<TableCell style={{ color: "white" }}>Index</TableCell>
<TableCell style={{ color: "white" }} align="middle">
Name
</TableCell>
<TableCell style={{ color: "white" }} align="middle">
Supplier
</TableCell>
<TableCell style={{ color: "white" }} align="middle">
Unit
</TableCell>
<TableCell style={{ color: "white" }} align="middle">
Unit Capacity
</TableCell>
<TableCell style={{ color: "white" }} align="middle">
Cost
</TableCell>
<TableCell style={{ color: "white" }} align="middle">
Daily Quantity Needed
</TableCell>
<TableCell
style={{
color: "white",
display: "flex",
justifyContent: "center",
}}
align="middle"
>
Action
</TableCell>
</TableRow>
</TableHead>
<TableBody>
{rows?.map((row) => (
<Row key={row.id} row={row} />
))}
</TableBody>
</Table>
</TableContainer>
</div>
);
}
export default React.memo(Ingredients);
And this is the PopOver:
import React from "react";
import { makeStyles } from "#material-ui/core/styles";
import Popover from "#material-ui/core/Popover";
import Typography from "#material-ui/core/Typography";
import { Button, IconButton } from "#material-ui/core";
import DeleteOutlineOutlinedIcon from "#material-ui/icons/DeleteOutlineOutlined";
import { useDispatch } from "react-redux";
import { productActions } from "redux/actions";
const useStyles = makeStyles((theme) => ({
typography: {
padding: theme.spacing(2),
},
}));
export default function PopOver(props) {
const { controller, id, role } = props;
const classes = useStyles();
const dispatch = useDispatch();
const [anchorEl, setAnchorEl] = React.useState(null);
const deleteProduct = (id) => {
if (!id) return;
dispatch(productActions.deleteProduct(id));
dispatch(productActions.getProducts(controller));
handleClose();
};
const handleClick = (event) => {
setAnchorEl(event.currentTarget);
};
const handleClose = () => {
setAnchorEl(null);
};
const open = Boolean(anchorEl);
const productId = open ? "simple-popover" : undefined;
return (
<div>
<Button aria-describedby={id} style={{ backgroundColor: "#FF4D4F", height: "40px", width: "20px" }} variant="contained" onClick={handleClick} disabled={role !== "Admin"}>
<IconButton aria-label="delete" color="secondary">
<DeleteOutlineOutlinedIcon style={{ color: "white" }} />
</IconButton>
</Button>
<Popover
id={productId}
open={open}
anchorEl={anchorEl}
onClose={handleClose}
anchorOrigin={{
vertical: "bottom",
horizontal: "center",
}}
transformOrigin={{
vertical: "top",
horizontal: "center",
}}
>
<Typography className={classes.typography}>
Do you want to delete this ingredient?
<Button
color="primary"
onClick={() => {
deleteProduct(id);
}}
>
Yes
</Button>
<Button color="secondary" onClick={handleClose}>
No
</Button>
</Typography>
</Popover>
</div>
);
}
These are the two actions that called when a record is deleted
const getProducts =
({ date, mode }) =>
async (dispatch) => {
const body = { date, mode };
dispatch({ type: types.GET_PRODUCTS_REQUEST, payload: null });
try {
const res = await api.post("/products", body);
dispatch({ type: types.GET_PRODUCTS_SUCCESS, payload: res.data.data });
} catch (error) {
toast.error("Get Product List Failed");
dispatch({ type: types.GET_PRODUCTS_FAILURE, payload: error });
}
};
const deleteProduct = (id) => async (dispatch) => {
dispatch({ type: types.DELETE_PRODUCT_REQUEST, payload: null });
try {
const res = await api.delete(`/products/${id}`);
dispatch({ type: types.DELETE_PRODUCT_SUCCESS, payload: res.data.data });
toast.success("Delete Product Success");
} catch (error) {
toast.error("Delete Product Fail");
dispatch({ type: types.DELETE_PRODUCT_FAILURE, payload: error });
}
};

Appbar not visible with Table on the same page - ReactJS

I'm new to ReactJS and I'm trying to put a table on a page with an AppBar. Both of these components are from Material UI, but only the Table is displayed, the AppBar seems to be just hidden.
I don't really get what is happening.
Here is the code (full):
import React from 'react';
import {Grid, Typography, Paper, Box, Toolbar, AppBar, ThemeProvider, createMuiTheme} from '#material-ui/core';
import Button from '#material-ui/core/Button';
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, makeStyles } from '#material-ui/core/styles';
const CustomCell = withStyles((theme) => ({
head: {
backgroundColor: '#3f51b5',
color: theme.palette.common.white,
},
body: {
fontSize: 14,
},
}))(TableCell);
const CustomRow = withStyles((theme) => ({
root: {
'&:nth-of-type(odd)': {
backgroundColor: theme.palette.action.hover,
},
},
}))(TableRow);
function createData(registration_nr, name, surname, e_mail) {
return {registration_nr, name, surname, e_mail};
}
const rows = [
createData('IE0001', 'Johnson', 'John', 'interesting_mail#domain.com'),
createData('IR0001', 'Dan', 'Thomas', 'interesting_mail#domain.com'),
createData('IA0011', 'Thompson', 'Bob', 'interesting_mail#domain.com'),
createData('MI0021', 'Martinez', 'Nancy', 'interesting_mail#domain.com'),
createData('MA0021', 'Gomez', 'Freddy', 'interesting_mail#domain.com'),
createData('ME0201', 'Charles', 'Diane', 'interesting_mail#domain.com'),
];
const useStyles = makeStyles({
table: {
minWidth: 300,
},
});
export default function BookView() {
const paperStyle = { padding: '0px 0px', width: 'auto', margin: '4px auto', textAlign: 'top-center', background: 'transparent', display: 'flex' }
const btnStyle = { width: '12vw', background: '#3f51b5', color: '#FFFFFF', height: '2.4vw', marginLeft: '40px', marginRight: '40px'}
const boxStyle = { background:'#FFFFFF', textAlign:'center', padding:'2px 2px', marginTop:9, justifyContent:'center', height:500 }
const narrowBox = { background:'#FFFFFF', textAlign:'center', padding:'0px 10px', width:'15%', margin:0, height:'100%'};
const container = { display: 'flex', justifyContent: 'center', fontSize:'1.12vw' }
// let day = getCurrentDate('-');
// const datas = [{ startDate: '2018-11-01T09:45', endDate: '2018-11-01T11:00', title: 'Just for the sake of working' }];
const classes = useStyles();
return (
<Grid>
<AppBar position='static' style={{background: '#757de8', marginTop: 'auto'}}>
<Toolbar gutterBottom>
<Paper style={paperStyle} elevation={0}>
<Button href="/signin" style={btnStyle}>Sign in</Button>
<Typography variant='h6' style={container}>The Library of 'Murica</Typography>
<Button href="/register" style={btnStyle}>Register</Button>
<Button href="/" style={btnStyle}>Home</Button>
</Paper>
</Toolbar>
</AppBar>
<Paper style={paperStyle} elevation={0}>
<TableContainer component={Grid}>
<Table className={classes.table} aria-label="customized table">
<TableHead>
<TableRow>
<CustomCell>Numar matricol</CustomCell>
<CustomCell align="right">Nume</CustomCell>
<CustomCell align="right">Prenume</CustomCell>
<CustomCell align="right">E-mail</CustomCell>
</TableRow>
</TableHead>
<TableBody>
{rows.map((row) => (
<CustomRow key={row.registration_nr}>
<CustomCell component="th" scope="row">{row.registration_nr}</CustomCell>
<CustomCell align="right">{row.name}</CustomCell>
<CustomCell align="right">{row.surname}</CustomCell>
<CustomCell align="right">{row.e_mail}</CustomCell>
</CustomRow>
))}
</TableBody>
</Table>
</TableContainer>
</Paper>
</Grid>
);
}
I tried with Paper, Box, but worthless. The table seems to be the only thing that is displayed on that page, no matter what I try.
Your code seems to be working fine on codesandbox, unless I'm missing something...

How can I create a button to a dialog box inside the PopperComponent of Material UI Labs Autocomplete

I have a Material UI Autocomplete which renders a list of Chips. I have added a button at the bottom of the PopperComponent which when clicked should open a dialog box.
But the Autocomplete doesn't allow the DialogBox to be opened. But the weird part is if I add 'open' to Autocomplete it works.
I have tried adding the onMouseDown event instead of onClick. Also, tried the event.preventDefault(). None of them works. However onMouseDown definitely called my listener for the Dialog box and changed its open state to true, but the dialog box did not appear.
This is the link to the sandbox.
Sandbox to the code
This is the component that implements the Dialog Box.
import React, { useState } from "react";
import { withStyles } from "#material-ui/core/styles";
import Button from "#material-ui/core/Button";
import Dialog from "#material-ui/core/Dialog";
import MuiDialogTitle from "#material-ui/core/DialogTitle";
import MuiDialogContent from "#material-ui/core/DialogContent";
import MuiDialogActions from "#material-ui/core/DialogActions";
import IconButton from "#material-ui/core/IconButton";
import CloseIcon from "#material-ui/icons/Close";
import Typography from "#material-ui/core/Typography";
import { orange } from "#material-ui/core/colors";
const styles = theme => ({
form: {
display: "flex",
flexDirection: "column",
margin: "auto",
width: "fit-content"
},
formControl: {
marginTop: theme.spacing(2),
minWidth: 120
},
formControlLabel: {
marginTop: theme.spacing(1)
},
closeButton: {
position: "absolute",
right: theme.spacing(1),
top: theme.spacing(1),
color: theme.palette.grey[500]
},
selectEmpty: {
marginTop: theme.spacing(2)
},
floatingLabelFocusStyle: {
color: "green"
},
separator: {
marginTop: theme.spacing(1)
},
menuStyle: {
border: "1px solid black",
borderRadius: "5%",
backgroundColor: "lightgrey"
}
});
const DialogTitle = withStyles(styles)(props => {
const { children, classes, onClose, ...other } = props;
return (
<MuiDialogTitle disableTypography className={classes.root} {...other}>
<Typography variant="h6">{children}</Typography>
{onClose ? (
<IconButton
aria-label="close"
className={classes.closeButton}
onClick={onClose}
>
<CloseIcon />
</IconButton>
) : null}{" "}
</MuiDialogTitle>
);
});
const DialogContent = withStyles(theme => ({
root: {
padding: theme.spacing(2)
}
}))(MuiDialogContent);
const DialogActions = withStyles(theme => ({
root: {
margin: 0,
padding: theme.spacing(1)
}
}))(MuiDialogActions);
const ActionButton = withStyles(theme => ({
root: {
color: "#E87424",
backgroundColor: "white",
"&:hover": {
backgroundColor: orange[100]
}
}
}))(Button);
const ManageTagButton = withStyles(theme => ({
root: {
color: "#E87424"
}
}))(Button);
const TagContainer = props => {
const [open, setOpen] = useState(false);
const handleClickOpen = () => {
console.log("Dialog box clicked");
setOpen(true);
};
const handleClose = () => {
setOpen(false);
};
return (
<div>
<ManageTagButton
onMouseDown={event => {
event.preventDefault();
handleClickOpen();
}}
size="small"
>
MANAGE TAGS
</ManageTagButton>
<Dialog
fullWidth
maxWidth={"sm"}
onClose={handleClose}
aria-labelledby="customized-dialog-title"
open={open}
>
<DialogTitle id="customized-dialog-title">Manage Tags</DialogTitle>
<DialogContent dividers>
<h1>
This is the component of the dialog box. In reality I neeed to
display a data table with CRUD operations to add more tags.
</h1>
</DialogContent>
<DialogActions>
<ActionButton autoFocus onClick={handleClose} color="secondary">
CLOSE
</ActionButton>
</DialogActions>
</Dialog>
</div>
);
};
export default TagContainer;
This is the component that implements the Autocomplete.
import React, { Fragment } from "react";
import Chip from "#material-ui/core/Chip";
import Autocomplete from "#material-ui/lab/Autocomplete";
import { withStyles } from "#material-ui/core/styles";
import { makeStyles } from "#material-ui/core/styles";
import TextField from "#material-ui/core/TextField";
import Button from "#material-ui/core/Button";
import List from "#material-ui/core/List";
import ListItem from "#material-ui/core/ListItem";
import ListItemText from "#material-ui/core/ListItemText";
import ListItemSecondaryAction from "#material-ui/core/ListItemSecondaryAction";
import Paper from "#material-ui/core/Paper";
import TagContainer from "./TagContainer";
const ListItemCustom = withStyles(theme => ({
gutters: {
paddingLeft: 0,
paddingRight: 0
},
secondaryAction: {
paddingRight: 0
}
}))(ListItem);
const AutocompleteCustom = withStyles(theme => ({
endAdornment: {
display: "none"
}
}))(Autocomplete);
const CreateButton = withStyles(theme => ({
root: {
color: "#E87424"
}
}))(Button);
const MuiFilledInputCustom = makeStyles(
{
underline: {
"&&&:before": {
borderBottom: "none"
},
"&&:after": {
borderBottom: "none"
}
}
},
{ name: "MuiFilledInput" }
);
const loadCustomStyles = () => {
MuiFilledInputCustom();
};
export default function AddTagToThread() {
loadCustomStyles();
const handleSubmit = () => {
console.log("Add tags to thread");
};
const useStyles = makeStyles({
root: {
minWidth: 300,
width: 300,
height: 250,
minHeight: 250,
zIndex: 1
},
buttons: {
display: "flex",
justifyContent: "flex-end"
}
});
const PaperComponentCustom = options => {
const classes = useStyles();
const { containerProps, children } = options;
return (
<Paper className={classes.root} {...containerProps} square>
{children}
<div className={classes.buttons}>
<TagContainer />
</div>
</Paper>
);
};
return (
<List dense={false}>
<ListItemCustom>
<ListItemText>
<AutocompleteCustom
multiple
id="size-small-filled-multi"
size="medium"
options={tagList}
noOptionsText="No options"
freeSolo
filterSelectedOptions
PaperComponent={PaperComponentCustom}
getOptionLabel={option => option.name}
onChange={(event, value) => {
console.log(value);
}}
renderTags={(value, getTagProps) =>
value.map((option, index) => (
<Chip
variant="default"
style={{
backgroundColor: option.color
}}
label={option.name}
size="medium"
{...getTagProps({ index })}
/>
))
}
renderOption={option => (
<Fragment>
<Chip
variant="default"
style={{
backgroundColor: option.color,
padding: "15px",
marginLeft: "12px"
}}
label={option.name}
size="medium"
/>
</Fragment>
)}
renderInput={params => (
<TextField
{...params}
variant="filled"
label="Filter By Tag"
placeholder="Select Tag"
/>
)}
/>
</ListItemText>
<ListItemSecondaryAction>
<CreateButton onClick={handleSubmit}>ADD TAG</CreateButton>
</ListItemSecondaryAction>
</ListItemCustom>
</List>
);
}
const tagList = [
{ name: "Follow Up", tagId: 1, color: "#FFC107" },
{ name: "Important", tagId: 2, color: "#46B978" },
{ name: "Idea", tagId: 3, color: "#EEA5F6" },
{ name: "Non Issue", tagId: 4, color: "#2EACE2" }
];
I have been stuck at this for last couple of days. Any help is greatly appreciated.
The issue with your code is that the <Dialog/> component is in the PaperComponentCustom component which gets unmounted after the option is selected.
<Paper className={classes.root} {...containerProps} square>
{children}
<ManageTagButton onMouseDown={handleClickOpen} fullWidth>
MANAGE TAGS
</ManageTagButton>
</Paper>
The solution to keep only the <ManageTagButton/> component in the PaperComponentCustom and move the <Dialog/> component one level up. I imagine that even if you have 10 elements in the <List/> you would still have only one <Dialog>, you cannot have 10 dialog components opened at once.
So therefore your <AddTagToThread/> component should render the dialog directly and the state of the dialog open and the handlers handleOpen and handleClose should be moved in the <AddTagToThread/> component also
Working codesandbox HERE, code below
Autocomplete component
import React, { Fragment, useState } from "react";
import Chip from "#material-ui/core/Chip";
import Autocomplete from "#material-ui/lab/Autocomplete";
import { withStyles } from "#material-ui/core/styles";
import { makeStyles } from "#material-ui/core/styles";
import TextField from "#material-ui/core/TextField";
import Button from "#material-ui/core/Button";
import List from "#material-ui/core/List";
import ListItem from "#material-ui/core/ListItem";
import ListItemText from "#material-ui/core/ListItemText";
import ListItemSecondaryAction from "#material-ui/core/ListItemSecondaryAction";
import Paper from "#material-ui/core/Paper";
import TagContainer from "./TagContainer";
const ListItemCustom = withStyles(theme => ({
gutters: {
paddingLeft: 0,
paddingRight: 0
},
secondaryAction: {
paddingRight: 0
}
}))(ListItem);
const AutocompleteCustom = withStyles(theme => ({
endAdornment: {
display: "none"
}
}))(Autocomplete);
const CreateButton = withStyles(theme => ({
root: {
color: "#E87424"
}
}))(Button);
const MuiFilledInputCustom = makeStyles(
{
underline: {
"&&&:before": {
borderBottom: "none"
},
"&&:after": {
borderBottom: "none"
}
}
},
{ name: "MuiFilledInput" }
);
const loadCustomStyles = () => {
MuiFilledInputCustom();
};
const ManageTagButton = withStyles(theme => ({
root: {
color: "#E87424"
}
}))(Button);
export default function AddTagToThread() {
loadCustomStyles();
const handleSubmit = () => {
console.log("Add tags to thread");
};
const [open, setOpen] = useState(false);
const handleClickOpen = () => {
console.log("Dialog box clicked");
setOpen(true);
};
const handleClose = () => {
setOpen(false);
};
const useStyles = makeStyles({
root: {
minWidth: 300,
width: 300,
height: 250,
minHeight: 250,
zIndex: 1
},
buttons: {
display: "flex",
justifyContent: "flex-end"
}
});
const PaperComponentCustom = options => {
const classes = useStyles();
const { containerProps, children } = options;
return (
<Paper className={classes.root} {...containerProps} square>
{children}
<ManageTagButton onMouseDown={handleClickOpen} fullWidth>
MANAGE TAGS
</ManageTagButton>
</Paper>
);
};
return (
<>
<TagContainer open={open} handleClose={handleClose} />
<List dense={false}>
<ListItemCustom>
<ListItemText>
<AutocompleteCustom
multiple
id="size-small-filled-multi"
size="medium"
options={tagList}
noOptionsText="No options"
freeSolo
filterSelectedOptions
PaperComponent={PaperComponentCustom}
getOptionLabel={option => option.name}
onChange={(event, value) => {
console.log(value);
}}
renderTags={(value, getTagProps) =>
value.map((option, index) => (
<Chip
variant="default"
style={{
backgroundColor: option.color
}}
label={option.name}
size="medium"
{...getTagProps({ index })}
/>
))
}
renderOption={option => (
<Fragment>
<Chip
variant="default"
style={{
backgroundColor: option.color,
padding: "15px",
marginLeft: "12px"
}}
label={option.name}
size="medium"
/>
</Fragment>
)}
renderInput={params => (
<TextField
{...params}
variant="filled"
label="Filter By Tag"
placeholder="Select Tag"
/>
)}
/>
</ListItemText>
<ListItemSecondaryAction>
<CreateButton onClick={handleSubmit}>ADD TAG</CreateButton>
</ListItemSecondaryAction>
</ListItemCustom>
</List>
</>
);
}
const tagList = [
{ name: "Follow Up", tagId: 1, color: "#FFC107" },
{ name: "Important", tagId: 2, color: "#46B978" },
{ name: "Idea", tagId: 3, color: "#EEA5F6" },
{ name: "Non Issue", tagId: 4, color: "#2EACE2" }
];
Dialog component
import React, { useState } from "react";
import { withStyles } from "#material-ui/core/styles";
import Button from "#material-ui/core/Button";
import Dialog from "#material-ui/core/Dialog";
import MuiDialogTitle from "#material-ui/core/DialogTitle";
import MuiDialogContent from "#material-ui/core/DialogContent";
import MuiDialogActions from "#material-ui/core/DialogActions";
import IconButton from "#material-ui/core/IconButton";
import CloseIcon from "#material-ui/icons/Close";
import Typography from "#material-ui/core/Typography";
import { orange } from "#material-ui/core/colors";
const styles = theme => ({
form: {
display: "flex",
flexDirection: "column",
margin: "auto",
width: "fit-content"
},
formControl: {
marginTop: theme.spacing(2),
minWidth: 120
},
formControlLabel: {
marginTop: theme.spacing(1)
},
closeButton: {
position: "absolute",
right: theme.spacing(1),
top: theme.spacing(1),
color: theme.palette.grey[500]
},
selectEmpty: {
marginTop: theme.spacing(2)
},
floatingLabelFocusStyle: {
color: "green"
},
separator: {
marginTop: theme.spacing(1)
},
menuStyle: {
border: "1px solid black",
borderRadius: "5%",
backgroundColor: "lightgrey"
}
});
const DialogTitle = withStyles(styles)(props => {
const { children, classes, onClose, ...other } = props;
return (
<MuiDialogTitle disableTypography className={classes.root} {...other}>
<Typography variant="h6">{children}</Typography>
{onClose ? (
<IconButton
aria-label="close"
className={classes.closeButton}
onClick={onClose}
>
<CloseIcon />
</IconButton>
) : null}{" "}
</MuiDialogTitle>
);
});
const DialogContent = withStyles(theme => ({
root: {
padding: theme.spacing(2)
}
}))(MuiDialogContent);
const DialogActions = withStyles(theme => ({
root: {
margin: 0,
padding: theme.spacing(1)
}
}))(MuiDialogActions);
const ActionButton = withStyles(theme => ({
root: {
color: "#E87424",
backgroundColor: "white",
"&:hover": {
backgroundColor: orange[100]
}
}
}))(Button);
const TagContainer = ({ open, handleClose }) => {
return (
<Dialog
fullWidth
maxWidth={"sm"}
onClose={handleClose}
aria-labelledby="customized-dialog-title"
open={open}
>
<DialogTitle id="customized-dialog-title">Manage Tags</DialogTitle>
<DialogContent dividers>
<h1>
This is the component of the dialog box. In reality I neeed to display
a data table with CRUD operations to add more tags.
</h1>
</DialogContent>
<DialogActions>
<ActionButton autoFocus onClick={handleClose} color="secondary">
CLOSE
</ActionButton>
</DialogActions>
</Dialog>
);
};
export default TagContainer;

Resources