React Material UI Menu Not Closing - javascript

I cannot for the life of me get this menu to close once it is opened on the page. I've tried moving the icon button tags and everything.
const useStyles = makeStyles((theme) => ({
root: {
flexGrow: 1,
},
menuButton: {
marginRight: theme.spacing(2),
},
title: {
flexGrow: 1,
},
}));
export default function ButtonAppBar() {
const classes = useStyles();
const [anchorEl, setAnchorEl] = React.useState(null);
const handleClick = (event) => {
setAnchorEl(event.currentTarget);
};
const handleClose = () => {
setAnchorEl(null);
};
return (
<div className={classes.root}>
<AppBar position="static">
<Toolbar>
<Typography variant="h6" className={classes.title}>
HPH
</Typography>
<IconButton edge="start" onClick={handleClick} className={classes.menuButton} color="inherit" aria-label="menu">
<MenuIcon />
<Menu
id="simple-menu"
anchorEl={anchorEl}
keepMounted
open={Boolean(anchorEl)}
onClose={handleClose}
>
<MenuItem button component={Link} to="/">
Home
</MenuItem>
<MenuItem button component={Link} to="/search">
Search Pricing
</MenuItem>
<MenuItem button component={Link} to="/about">
About
</MenuItem>
</Menu>
</IconButton>
</Toolbar>
</AppBar>
</div>
);
}
When I put the menu outside of the icon button tag, the icon no longer allows any click event.

You need to move the menu out of the button
export default function ButtonAppBar() {
const classes = useStyles();
const [anchorEl, setAnchorEl] = React.useState(null);
const handleClick = (event) => {
setAnchorEl(event.currentTarget);
};
const handleClose = () => {
setAnchorEl(null);
};
return (
<div className={classes.root}>
<AppBar position="static">
<Toolbar>
<Typography variant="h6" className={classes.title}>
HPH
</Typography>
<IconButton edge="start" onClick={handleClick} className={classes.menuButton} color="inherit" aria-label="menu">
<MenuIcon />
</IconButton>
<Menu
id="simple-menu"
anchorEl={anchorEl}
keepMounted
open={Boolean(anchorEl)}
onClose={handleClose}
>
<MenuItem button component={Link} to="/">
Home
</MenuItem>
<MenuItem button component={Link} to="/search">
Search Pricing
</MenuItem>
<MenuItem button component={Link} to="/about">
About
</MenuItem>
</Menu>
</Toolbar>
</AppBar>
</div>
);
}
See the simple menu example

Related

How to declare one button in a react component and update the title of it in another?

I was wondering if anyone could tell me the best way to dyamically change the button title I'm using in the PopUp component to change the title to 'login' or 'signup' depending on what component I'm passing into the NavBar?
I'm returning a and form into each PopUp component in the navbar as children but have gotten a bit stuck on how to get the title to change. Any help would be much appreciated.
const BootstrapDialog = styled(Dialog)(({ theme }) => ({
"& .MuiDialogContent-root": {
padding: theme.spacing(2),
},
"& .MuiDialogActions-root": {
padding: theme.spacing(1),
},
}));
const BootstrapDialogTitle = (props) => {
const { children, onClose, ...other } = props;
return (
<DialogTitle sx={{ m: 0, p: 2 }} {...other}>
{children}
{onClose ? (
<IconButton
aria-label="close"
onClick={onClose}
sx={{
position: "absolute",
right: 8,
top: 8,
color: (theme) => theme.palette.grey[500],
}}
>
<CloseIcon />
</IconButton>
) : null}
</DialogTitle>
);
};
BootstrapDialogTitle.propTypes = {
children: PropTypes.node,
onClose: PropTypes.func.isRequired,
};
export function PopUp(props) {
const [open, setOpen] = React.useState(false);
const handleClickOpen = () => {
setOpen(true);
};
const handleClose = () => {
setOpen(false);
};
return (
<div>
<Button color="inherit" onClick={handleClickOpen}>
SignUp
</Button>
<BootstrapDialog
onClose={handleClose}
aria-labelledby="customized-dialog-title"
open={open}
>
<BootstrapDialogTitle
id="customized-dialog-title"
onClose={handleClose}
>
<Logo />
</BootstrapDialogTitle>
<DialogContent dividers>{props.children}</DialogContent>
</BootstrapDialog>
</div>
);
}
export default function NavBar() {
return (
<Box sx={{ flexGrow: 1 }}>
<AppBar position="fixed">
<Toolbar>
<IconButton
size="large"
edge="start"
color="inherit"
aria-label="menu"
sx={{ mr: 2 }}
>
<MenuIcon />
</IconButton>
<Typography variant="h6" component="div" sx={{ flexGrow: 1 }}>
<Logo />
</Typography>
<PopUp>
<Login />
</PopUp>
<PopUp>
<SignUp />
</PopUp>
<Button color="inherit">About</Button>
</Toolbar>
</AppBar>
</Box>
);
}

Material-table with MUI full screen dialog

Problem: Clicking a button in my material-table it opens the full screen dialog then closing the dialog, Then I am not able to click anywhere in the screen anymore. The dialog's wrapper container blocking the whole screen.
My material ui table component:
export default function MyMaterialTable() {
const columns = [
// columns here
];
const [myState, setModalState] = React.useState(false);
function modalHandleClick() {
setModalState(!myState);
}
return (
<div>
<MaterialTable
title="My Material Table"
columns={columns} data={tableData} // Retreived via api
options={{
selection: true,
filtering: true,
paging: true
}}
actions={[
{
tooltip: 'Action button that triggers the Fullscreen Dialog',
icon: () => {return(<AddBoxIcon /> )},
onClick: (evt, data) => modalHandleClick()
}
]}
/>
<MyFullScreenDialog modalState={myState} modalHandleClick={modalHandleClick} />
</div>
);
}
My Full Screen dialog component:
export default function MyFullScreenDialog (props) {
const Transition = React.forwardRef(function Transition(p, ref) {
return <Slide direction="up" ref={ref} {...p} />;
});
const handleClose = () => {
props.modalHandleClick();
};
return(
<div>
<Dialog
fullScreen
open={props.modalState}
onClose={handleClose}
TransitionComponent={Transition}
>
<AppBar sx={{ position: 'relative' }}>
<Toolbar>
<IconButton
edge="start"
color="inherit"
onClick={handleClose}
aria-label="close"
>
<CloseIcon />
</IconButton>
<Typography sx={{ ml: 2, flex: 1 }} variant="h6" component="div">
Sound
</Typography>
<Button autoFocus color="inherit" onClick={handleClose}>
save
</Button>
</Toolbar>
</AppBar>
<List>
<ListItem button>
<ListItemText primary="Phone ringtone" secondary="Titania" />
</ListItem>
<Divider />
<ListItem button>
<ListItemText
primary="Default notification ringtone"
secondary="Tethys"
/>
</ListItem>
</List>
</Dialog>
</div>
);
}
I am following these guides:
FullScreen Dialog MUI
Material Table
I think the problem is in your Transition.
Try declaring the const Transition in a global context, outside the class declaration.
In your Fullscreen component:
const Transition = React.forwardRef(function Transition(p, ref) {
return <Slide direction="up" ref={ref} {...p} />;
});
export default function MyFullScreenDialog (props) {
const handleClose = () => {
props.modalHandleClick();
};
return(
<div>
...

Conditionally Rendering Material UI Elements in React

I want to render Material UI Elements like MenuItem of a AppBar Conditionally if some conditions are true. In my example menu items should only be rendered for specific users. But it doesnt work like the way it would work with normal html in react.
{context.token && context.userRole === "USER" && (
<MenuItem key="submission" onClick={handleCloseNavMenu}>
<Typography textAlign="center">Submission</Typography>
</MenuItem>
)}
{context.token && context.userRole === "JUDGE" && (
<MenuItem key="submissions" onClick={handleCloseNavMenu}>
<Typography textAlign="center">Submissions</Typography>
</MenuItem>
)}
Its rendering this Items all the time anyways and seems to ignoring the conditions.
The full code:
import React from "react";
import { NavLink } from "react-router-dom";
import AuthContext from "../context/auth-context.js";
import AppBar from "#mui/material/AppBar";
import Box from "#mui/material/Box";
import Toolbar from "#mui/material/Toolbar";
import IconButton from "#mui/material/IconButton";
import Typography from "#mui/material/Typography";
import Menu from "#mui/material/Menu";
import MenuIcon from "#mui/icons-material/Menu";
import Container from "#mui/material/Container";
import Avatar from "#mui/material/Avatar";
import Button from "#mui/material/Button";
import Tooltip from "#mui/material/Tooltip";
import MenuItem from "#mui/material/MenuItem";
import ComputerIcon from "#mui/icons-material/Computer";
const ResponsiveAppBar = (props) => {
const pages = ["Conditions", "Winner", "Submission", "Submissions", "Login"];
const settings = ["Profile", "Settings", "Logout"];
const [anchorElNav, setAnchorElNav] = React.useState(null);
const [anchorElUser, setAnchorElUser] = React.useState(null);
const handleOpenNavMenu = (event) => {
setAnchorElNav(event.currentTarget);
};
const handleOpenUserMenu = (event) => {
setAnchorElUser(event.currentTarget);
};
const handleCloseNavMenu = () => {
setAnchorElNav(null);
};
const handleCloseUserMenu = () => {
setAnchorElUser(null);
};
return (
<AuthContext.Consumer>
{(context) => (
<AppBar position="static">
<Container maxWidth="xl">
<Toolbar disableGutters>
<Typography
variant="h6"
noWrap
component="div"
sx={{ mr: 2, display: { xs: "none", md: "flex" } }}
>
<ComputerIcon />
</Typography>
<Box sx={{ flexGrow: 1, display: { xs: "flex", md: "none" } }}>
<IconButton
size="large"
aria-label="account of current user"
aria-controls="menu-appbar"
aria-haspopup="true"
onClick={handleOpenNavMenu}
color="inherit"
>
<MenuIcon />
</IconButton>
<Menu
id="menu-appbar"
anchorEl={anchorElNav}
anchorOrigin={{
vertical: "bottom",
horizontal: "left",
}}
keepMounted
transformOrigin={{
vertical: "top",
horizontal: "left",
}}
open={Boolean(anchorElNav)}
onClose={handleCloseNavMenu}
sx={{
display: { xs: "block", md: "none" },
}}
>
{context.token && context.userRole === "USER" && (
<MenuItem key="submission" onClick={handleCloseNavMenu}>
<Typography textAlign="center">Submission</Typography>
</MenuItem>
)}
{context.token && context.userRole === "JUDGE" && (
<MenuItem key="submissions" onClick={handleCloseNavMenu}>
<Typography textAlign="center">Submissions</Typography>
</MenuItem>
)}
<MenuItem key="conditions" onClick={handleCloseNavMenu}>
<Typography textAlign="center">Conditions</Typography>
</MenuItem>
<MenuItem key="winner" onClick={handleCloseNavMenu}>
<Typography textAlign="center">Winner</Typography>
</MenuItem>
</Menu>
</Box>
<Typography
variant="h6"
noWrap
component="div"
sx={{ flexGrow: 1, display: { xs: "flex", md: "none" } }}
>
LOGO
</Typography>
<Box sx={{ flexGrow: 1, display: { xs: "none", md: "flex" } }}>
{pages.map((page) => (
<Button
key={page}
onClick={handleCloseNavMenu}
sx={{ my: 2, color: "white", display: "block" }}
>
{page}
</Button>
))}
</Box>
<Box sx={{ flexGrow: 0 }}>
<Tooltip title="Open settings">
<IconButton onClick={handleOpenUserMenu} sx={{ p: 0 }}>
<Avatar
alt="Remy Sharp"
src="/static/images/avatar/2.jpg"
/>
</IconButton>
</Tooltip>
<Menu
sx={{ mt: "45px" }}
id="menu-appbar"
anchorEl={anchorElUser}
anchorOrigin={{
vertical: "top",
horizontal: "right",
}}
keepMounted
transformOrigin={{
vertical: "top",
horizontal: "right",
}}
open={Boolean(anchorElUser)}
onClose={handleCloseUserMenu}
>
{settings.map((setting) => (
<MenuItem key={setting} onClick={handleCloseNavMenu}>
<Typography textAlign="center">{setting}</Typography>
</MenuItem>
))}
</Menu>
</Box>
</Toolbar>
</Container>
</AppBar>
)}
</AuthContext.Consumer>
);
};
export default ResponsiveAppBar;

Material UI- My Card Component is getting added to my Appbar. I want the cards to show up once a button the Appbar is clicked

The naming conventions are off. Please ignore those.
Part of the code for the Appbar:
const useStyles = makeStyles((theme) => ({
root: {
flexGrow: 1
},
title: {
flexGrow: 1
}
}));
export default function Appp() {
const classes = useStyles();
const history = useHistory();
return (
<div className={classes.root}>
<Router>
<AppBar position="static" display="flex">
<Toolbar>
<Typography variant="h6" className={classes.title}>
Employee Management
</Typography>
<Button
variant="contained"
color="secondary"
className={classes.button}
>
<Link to="/emp">Fetch Employees</Link>
</Button>
<Switch>
<Route exact path="/emp" render={(props) => <App {...props} />} />
</Switch>
</Toolbar>
</AppBar>
<br/>
</Router>
</div>
);
}
The App component ("user" is JSON data received from an API call):
return (
<div className="App">
{user &&
user.map((singleUser) => {
return (
<SimpleCard
nam={singleUser.name}
uname={singleUser.username}
ph={singleUser.phone}
wb={singleUser.website}
></SimpleCard>
);
})}
</div>
);
}
The SimpleCard Component:
export default function SimpleCard(props) {
const classes = useStyles();
return (
<Card padding={6} style={{ backgroundColor: "red", display: "inline-block" }}>
<CardContent>
<Typography
className={classes.title}
color="textSecondary"
gutterBottom
>
<h1>{props.nam}</h1>
</Typography>
<Typography variant="h5" component="h5">
#{props.uname}
</Typography>
<Typography className={classes.pos} color="textPrimary">
adjective
</Typography>
<Typography variant="body2" component="p">
well meaning and kindly.
<br />
</Typography>
</CardContent>
</Card>
);
}
So when the Fetch Employees button is clicked, I want the cards with the information to show up. However they are just getting added in the Appbar and the UI is a mess.
return (
<div className={classes.root}>
<Router>
<AppBar position="static" display="flex">
<Toolbar>
<Typography variant="h6" className={classes.title}>
Employee Management
</Typography>
<Button
variant="contained"
color="secondary"
className={classes.button}
>
<Link to="/emp">Fetch Employees</Link>
</Button>
</Toolbar>
</AppBar>
<br/>
<Switch>
<Route exact path="/emp" render={(props) => <App {...props} />} />
</Switch>
</Router>
</div>
);
You just need to remove your navigator out of the bar

React and Material UI: how can I expand only one single card

I'm using React and Material UI in order to show some mapped cards mapped. When I try to expand a card, all the cards are expanded at the same time. I figured out that I have to pass an index inside my "handleExpandClick" function, but still not working. Maybe I did it some kind of typo.
I found this question Expand one card on click that regards the same problem, but seems not to be applied to my situation.
Here my piece of code:
const useStyles = makeStyles(theme => ({
card: {
maxWidth: 345,
marginBottom: 15
},
media: {
height: 0,
paddingTop: "56.25%" // 16:9
},
expand: {
transform: "rotate(0deg)",
marginLeft: "auto",
transition: theme.transitions.create("transform", {
duration: theme.transitions.duration.shortest
})
},
expandOpen: {
transform: "rotate(180deg)"
},
avatar: {
width: 90
},
root: {
display: "flex",
justifyContent: "center",
flexWrap: "wrap",
"& > *": {
margin: theme.spacing(0.5)
}
},
list: {
width: 200
}
}));
const ItininerariesList = ({ itineraries, activities }) => {
const classes = useStyles();
const [expanded, setExpanded] = React.useState(false);
let path = window.location.pathname;
let currentId = path.substring(path.lastIndexOf("/") + 1);
const itinerariesPerCity = itineraries.filter(
itiner => itiner.city_id === currentId
);
const handleExpandClick = () => {
setExpanded(!expanded);
};
return (
<Fragment>
{itinerariesPerCity.map((itinerary, i) => (
<Card className={classes.card} key={itinerary._id}>
<CardHeader
avatar={
<Grid
container
direction="column"
justify="flex-start"
alignItems="center"
className={classes.avatar}
>
<Avatar
aria-label="user"
alt={itinerary.profile_name}
src={itinerary.profile_img}
>
<PersonIcon />
</Avatar>
<Typography variant="caption" component="p">
{itinerary.profile_name}
</Typography>
</Grid>
}
action={
<IconButton aria-label="settings">
<MoreVertIcon />
</IconButton>
}
title={itinerary.title}
subheader={itinerary.sub_title}
/>
<CardContent>
</CardContent>
<CardActions disableSpacing>
<IconButton aria-label="add to favorites">
<FavoriteIcon />
</IconButton>
<IconButton aria-label="share">
<ShareIcon />
</IconButton>
<IconButton
className={clsx(classes.expand, {
[classes.expandOpen]: expanded
})}
onClick={() => handleExpandClick()}
aria-expanded={expanded}
aria-label="show more"
>
<ExpandMoreIcon />
</IconButton>
</CardActions>
<Collapse in={expanded} timeout="auto" unmountOnExit>
<CardContent>
<ActivitiesList
activities={activities}
itineraryId={itinerary._id}
/>
</CardContent>
</Collapse>
</Card>
))}
</Fragment>
);
};
export default ItininerariesList;
Any suggestions or guidance would be greatly appreciated. Thank you in advance.
In the expand handler you indeed have to pass the index. And also use it in the state.
Something like it:
const [expandedId, setExpandedId] = React.useState(-1);
...
const handleExpandClick = (i) => {
setExpandedId(expandedId === i ? -1 : i);
};
...
<CardContent />
<CardActions disableSpacing>
<IconButton aria-label="add to favorites">
<FavoriteIcon />
</IconButton>
<IconButton aria-label="share">
<ShareIcon />
</IconButton>
<IconButton
onClick={() => handleExpandClick(i)}
aria-expanded={expandedId === i}
aria-label="show more"
>
<ExpandMoreIcon />
</IconButton>
</CardActions>
<Collapse in={expandedId === i} timeout="auto" unmountOnExit>
<CardContent>
<div>ActivitiesList</div>
</CardContent>
</Collapse>
Here is a working example: https://codesandbox.io/s/eloquent-sara-wswrn

Categories

Resources