ReactJS: Close automatically the menu when change page - javascript

I have a create a nested menu, but I have a problem with it.
I have :
Parent_Menu
Parent1
> Child_Menu1
> Child_Menu2
Parent2
Now if I click for example in Child_Menu1, i'm redirect to the page correctly and also the Parent1 menu is closed, but the Parent_Menu reamins opened (So i can click another time or in parent1 or in parent2).
I would to close all the menu (the parent_menu) when I change page.
import React, { useState } from 'react';
import MenuItem from 'app/shared/layout/menus/menu-item';
import { Dropdown, DropdownToggle, DropdownMenu, UncontrolledDropdown, DropdownItem, NavLink } from 'reactstrap';
import { NavDropdown } from './menu-components';
export const EntitiesMenu = props => {
const [dropDownOpen, setDropDownOpen] = useState(false);
const toggle = () => setDropDownOpen(prevState => !prevState);
return (
<NavDropdown
icon="th-list"
name="Parent_Menu"
id="parent-menu"
data-cy="parent_menu"
style={{ maxHeight: '80vh', minWidth: '150px', minHeight: '250px' }}
>
<Dropdown isOpen={dropDownOpen} toggle={toggle} direction="right">
<DropdownToggle nav caret style={{ color: '#000000', marginLeft: 25 }}>
Parent1
</DropdownToggle>
<DropdownMenu right style={{ border: '0px', outline: 'none', marginTop: 20 }}>
<DropdownItem>
<MenuItem icon="asterisk" to="/child_menu1">
Child_Menu1
</MenuItem>
</DropdownItem>
<DropdownItem>
<MenuItem icon="asterisk" to="/child_menu2">
Child_Menu2
</MenuItem>
</DropdownItem>
</DropdownMenu>
<NavLink href="/parent2" style={{ color: '#000000', marginLeft: 25 }}>
Parent2
</NavLink>
</Dropdown>
</NavDropdown>
);
};
How can I do to close automatically all the menu?

have you try the onBlur?
or you can even use the onClick
import React, { useState } from 'react';
import MenuItem from 'app/shared/layout/menus/menu-item';
import { Dropdown, DropdownToggle, DropdownMenu, UncontrolledDropdown, DropdownItem, NavLink } from 'reactstrap';
import { NavDropdown } from './menu-components';
export const EntitiesMenu = props => {
const [dropDownOpen, setDropDownOpen] = useState(false);
const toggle = () => setDropDownOpen(prevState => !prevState);
return (
<NavDropdown
icon="th-list"
name="Parent_Menu"
id="parent-menu"
data-cy="parent_menu"
style={{ maxHeight: '80vh', minWidth: '150px', minHeight: '250px' }}
>
<Dropdown isOpen={dropDownOpen} toggle={toggle} direction="right">
<DropdownToggle nav caret style={{ color: '#000000', marginLeft: 25 }}>
Parent1
</DropdownToggle>
<DropdownMenu onBlur={e=>{
toggle()
}} right style={{ border: '0px', outline: 'none', marginTop: 20 }}>
<DropdownItem>
<MenuItem onClick={()=>{
toggle()
}} icon="asterisk" to="/child_menu1">
Child_Menu1
</MenuItem>
</DropdownItem>
<DropdownItem>
<MenuItem onClick={()=>{
toggle()
}} icon="asterisk" to="/child_menu2">
Child_Menu2
</MenuItem>
</DropdownItem>
</DropdownMenu>
<NavLink onClick={()=>{
toggle()
}} href="/parent2" style={{ color: '#000000', marginLeft: 25 }}>
Parent2
</NavLink>
</Dropdown>
</NavDropdown>
);
};

import React, { useState } from 'react';
import MenuItem from 'app/shared/layout/menus/menu-item';
import { Dropdown, DropdownToggle, DropdownMenu, UncontrolledDropdown, DropdownItem, NavLink } from 'reactstrap';
import { NavDropdown } from './menu-components';
export const EntitiesMenu = props => {
const [dropDownOpen, setDropDownOpen] = useState(false);
const [dropDownStyle, setStyle] = useState('80px');
const toggle = () => setDropDownOpen(prevState => !prevState);
useEffect(()=>{
dropDownOpen ? setStyle('0'); : setStyle('80px');
},[dropDownOpen]);
return (
<NavDropdown
icon="th-list"
name="Parent_Menu"
id="parent-menu"
data-cy="parent_menu"
style={{ maxHeight: customHeight, minWidth: '150px', minHeight: '250px' }}
>
<Dropdown isOpen={dropDownOpen} toggle={toggle} direction="right">
<DropdownToggle nav caret style={{ color: '#000000', marginLeft: 25 }}>
Parent1
</DropdownToggle>
<DropdownMenu right style={{ border: '0px', outline: 'none', marginTop: 20 }}>
<DropdownItem>
<MenuItem icon="asterisk" to="/child_menu1">
Child_Menu1
</MenuItem>
</DropdownItem>
<DropdownItem>
<MenuItem icon="asterisk" to="/child_menu2">
Child_Menu2
</MenuItem>
</DropdownItem>
</DropdownMenu>
<NavLink href="/parent2" style={{ color: '#000000', marginLeft: 25 }}>
Parent2
</NavLink>
</Dropdown>
</NavDropdown>
);
};

Related

Selecting another mui tab breaks css from Google code prettify CDN

This is my site with this issue.
I'm coding a blog in ReactJS. In this article section, I use a mui Tabs and three mui Tabs like this to take apart an article into description, code and others parts. In description and code parts, I use google-code-prettify.
It works when I load the description page but it doesn't work when I click code or others page and then back to the description page.
BasicTabs.js
import React, { useState } from 'react';
import Box from '#mui/material/Box';
import Tab from '#mui/material/Tab';
import Tabs from '#mui/material/Tabs';
import CreateTabPanel from "./TabPanel";
export default function CreateBasicTabs(props) {
const [value, setValue] = useState(0);
const handleChange = (event, newValue) => {
setValue(newValue);
};
function a11yProps(index) {
return {
id: `simple-tab-${index}`,
'aria-controls': `simple-tabpanel-${index}`,
};
}
const boxSx = {
position: 'sticky',
top: props.breadcrumbsHeight + 9.5,
borderBottomLeftRadius: 10,
borderBottomRightRadius: 10,
}
const boxSxForTablet = {
position: 'sticky',
top: props.appBarHeight - 0.5,
borderBottomLeftRadius: 0,
borderBottomRightRadius: 0,
}
return (
<Box sx={{ width: '100%' }}>
<Box
sx={props.isTablet ? boxSxForTablet : boxSx}
className={`pop-up ${props.isScrolling && 'active shadow-active'}`}
>
<Tabs
value={value}
onChange={handleChange}
aria-label="basic tabs example"
sx={{ paddingLeft: 4 }}
>
<Tab label="Detail" {...a11yProps(0)} sx={{ textTransform: 'none' }} />
<Tab label="Code" {...a11yProps(1)} sx={{ textTransform: 'none' }} />
<Tab label="Others" {...a11yProps(2)} sx={{ textTransform: 'none' }} />
</Tabs>
</Box>
<CreateTabPanel value={value} />
</Box >
);
}
TabPanel.js
import React from 'react';
import Box from '#mui/material/Box';
import PropTypes from 'prop-types';
import Typography from '#mui/material/Typography';
import { data } from "../assets/data";
import { useSearchParams } from "react-router-dom";
function getArticleContent() {
const [searchParams] = useSearchParams();
const articleTitle = searchParams.get('title');
for (const item of data) {
if (articleTitle === item.query) {
return item.content;
}
}
}
function TabPanel(tabProps) {
const { children, value, index, ...other } = tabProps;
return (
<div
role="tabpanel"
hidden={value !== index}
id={`simple-tabpanel-${index}`}
aria-labelledby={`simple-tab-${index}`}
style={{
backgroundColor: 'rgb(255, 255, 255)',
borderRadius: 10,
marginLeft: 30,
marginRight: 30,
marginBottom: 30,
}}
{...other}
className='shadow-active'
>
{value === index && (
<Box
sx={{
p: 3,
marginBottom: 10,
}}
>
<Typography>
{children}
</Typography>
</Box>
)}
</div>
);
}
export default function CreateTabPanel(props) {
return (
<>
<TabPanel value={props.value} index={0}>
<div
dangerouslySetInnerHTML={{ __html: getArticleContent() }}
/>
</TabPanel>
<TabPanel value={props.value} index={1}>
<div
dangerouslySetInnerHTML={{ __html: getArticleContent() }}
/>
</TabPanel>
<TabPanel value={props.value} index={2}>
Item Three
</TabPanel>
</>
);
}
CreateTabPanel.propTypes = {
children: PropTypes.node,
index: PropTypes.number.isRequired,
value: PropTypes.number.isRequired,
};
These are screen captures of when it is loaded and when I back to the page.
The second capture looks like blackout but this is because it's css from google-code-prettify works
pre.prettyprint {
border: 0 solid #888;
}
.prettyprint {
background: #000;
}
Could you tell me why it does not work?

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;

ReactJS: Menu with submenu (nested)

I have created a menu with submenu nested like:
- Example1 >
Example1.1
Example1.2
- Example2 >
Example2.1
So if I click on Example, it opens a submenu with two fields Example1 and Example2.
This is the code that I use: (with reactstrap)
export const ExampleMenu = props => {
const [dropDownOpen, setDropDownOpen] = useState(false);
const toggle = () => setDropDownOpen(prevState => !prevState);
useEffect( () => {
setDropDownOpen(false)
})
return (
<NavDropdown
icon="th-list"
name="Example"
id="example-menu"
data-cy="example"
style={{ maxHeight: '80vh', minWidth: '300px', minHeight: '150px', overflow: 'auto' }}
>
<Dropdown isOpen={dropDownOpen} toggle={toggle} rigth>
<UncontrolledDropdown nav direction="right">
<DropdownToggle nav caret style={{ color: '#000000' }}>
Example1
</DropdownToggle>
<DropdownMenu right style={{ marginLeft: 90, border: '0px', outline: 'none' }}>
<DropdownItem>
<MenuItem icon="asterisk" to="/example1_1">
Example1.1
</MenuItem>
</DropdownItem>
<DropdownItem>
<MenuItem icon="asterisk" to="/example1_2">
Example1.2
</MenuItem>
</DropdownItem>
</DropdownMenu>
</UncontrolledDropdown>
<UncontrolledDropdown nav direction="right">
<DropdownToggle nav caret style={{ color: '#000000' }}>
Example2
</DropdownToggle>
<DropdownMenu right style={{ marginLeft: 90, border: '0px', outline: 'none' }}>
<DropdownItem>
<MenuItem icon="asterisk" to="/example2_1">
Example2.1
</MenuItem>
</DropdownItem>
</DropdownMenu>
</UncontrolledDropdown>
</Dropdown>
</NavDropdown>
Now my problem is that if i click on submenu like Example1.2, I change the page but the parent menu ( the menu with Example1 and Example2) remains open and i need to click anyway out of the menu to close it.
How can I do to close automatically when I click in submenu category?

Certain components show fail to show up on screen and inspect element isn't helping

I'm trying to design a UI that looks like this
So far what I have is this
The problem I'm having is getting the info icon to show up where it's supposed to be and getting the direct text and create icon on the top left corner. I also can't have the primary and general show up in my UI like Instagrams and the scrollbar on my drawer goes all the way up instead of stopping where the appbar is.
Here's my code
import React from "react";
import { makeStyles, withStyles } from "#material-ui/core/styles";
import Drawer from "#material-ui/core/Drawer";
import AppBar from "#material-ui/core/AppBar";
import Toolbar from "#material-ui/core/Toolbar";
import List from "#material-ui/core/List";
import Typography from "#material-ui/core/Typography";
import Divider from "#material-ui/core/Divider";
import ListItem from "#material-ui/core/ListItem";
import ListItemText from "#material-ui/core/ListItemText";
import Avatar from "#material-ui/core/Avatar";
import PersonIcon from "#material-ui/icons/Person";
import Badge from "#material-ui/core/Badge";
import InfoIcon from "#material-ui/icons/Info";
import ListItemAvatar from "#material-ui/core/ListItemAvatar";
import { connect } from "react-redux";
function mapStateToProps(state) {
return {};
}
const drawerWidth = 240;
const useStyles = makeStyles((theme) => ({
root: {
display: "flex",
},
appBar: {
width: `calc(100% - ${drawerWidth}px)`,
backgroundColor: "#fff",
},
drawer: {
width: drawerWidth,
flexShrink: 0,
},
drawerPaper: {
width: drawerWidth,
},
// necessary for content to be below app bar
toolbar: theme.mixins.toolbar,
content: {
flexGrow: 1,
backgroundColor: theme.palette.background.default,
padding: theme.spacing(3),
},
}));
const SmallAvatar = withStyles((theme) => ({
root: {
width: 11,
height: 11,
color: "green",
backgroundColor: "green",
},
}))(Avatar);
const Messaging = () => {
const classes = useStyles();
const dummy = "Active now";
return (
<div className={classes.root}>
<AppBar position='fixed' className={classes.appBar}>
<Toolbar style={{ width: "100%" }}>
<Avatar>
<PersonIcon />
</Avatar>
<Typography variant='h6'>adib.akm</Typography>
<InfoIcon />
</Toolbar>
</AppBar>
<Drawer
className={classes.drawer}
variant='permanent'
classes={{
paper: classes.drawerPaper,
}}
anchor='left'>
<div className={classes.toolbar} />
<Divider />
<List>
<ListItem>
<ListItemAvatar>
<Badge
overlap='circle'
anchorOrigin={{
vertical: "bottom",
horizontal: "right",
}}
badgeContent={<SmallAvatar />}>
<Avatar>
<PersonIcon />
</Avatar>
</Badge>
</ListItemAvatar>
<ListItemText primary='Photos' secondary={dummy} />
</ListItem>
<ListItem>
<ListItemAvatar>
<Badge
overlap='circle'
anchorOrigin={{
vertical: "bottom",
horizontal: "right",
}}
badgeContent={<SmallAvatar />}>
<Avatar>
<PersonIcon />
</Avatar>
</Badge>
</ListItemAvatar>
<ListItemText primary='Work' secondary={dummy} />
</ListItem>
<ListItem>
<ListItemAvatar>
<Badge
overlap='circle'
anchorOrigin={{
vertical: "bottom",
horizontal: "right",
}}
badgeContent={<SmallAvatar />}>
<Avatar>
<PersonIcon />
</Avatar>
</Badge>
</ListItemAvatar>
<ListItemText primary='Vacation' secondary={dummy} />
</ListItem>
</List>
</Drawer>
</div>
);
};
export default connect(mapStateToProps)(Messaging);
This is the codesandbox https://codesandbox.io/s/mutable-monad-dsvf8?file=/src/index.js

How to align Material-UI Menu items?

I use the menu and menu item of material-ui to build a select dropdown menu, but I found one thing strange: the dropdown menu always expand to the left side of the box, as the image shown below:
I've tried to use the alignItems property inside my <MenuItem> but it didn't work.
My code is shown below. Can anybody help me to fix this problem? I really appreciate your help!
<Menu
id="order-menu"
anchorEl={anchorEl}
keepMounted
open={Boolean(anchorEl)}
onClose={() => setAnchorEl(null)}
>
{options.map((option, index) => (
<MenuItem
key={option}
selected={index === selectedIndex}
onClick={(event) => handleMenuItemClick(event, index)}
>
{option}
</MenuItem>
))}
</Menu>
The default styles controlling this are in ListItem where it specifies justifyContent: 'flex-start'.
You can change this to be right aligned with:
const MenuItem = withStyles({
root: {
justifyContent: "flex-end"
}
})(MuiMenuItem);
Here's a full working example:
import React from "react";
import Button from "#material-ui/core/Button";
import Menu from "#material-ui/core/Menu";
import MuiMenuItem from "#material-ui/core/MenuItem";
import { withStyles } from "#material-ui/core/styles";
const MenuItem = withStyles({
root: {
justifyContent: "flex-end"
}
})(MuiMenuItem);
export default function SimpleMenu() {
const [anchorEl, setAnchorEl] = React.useState(null);
const handleClick = event => {
setAnchorEl(event.currentTarget);
};
const handleClose = () => {
setAnchorEl(null);
};
return (
<div>
<Button
aria-controls="simple-menu"
aria-haspopup="true"
onClick={handleClick}
>
Open Menu
</Button>
<Menu
id="simple-menu"
anchorEl={anchorEl}
keepMounted
open={Boolean(anchorEl)}
onClose={handleClose}
>
<MenuItem onClick={handleClose}>1</MenuItem>
<MenuItem onClick={handleClose}>2</MenuItem>
<MenuItem onClick={handleClose}>3</MenuItem>
<MenuItem onClick={handleClose}>10</MenuItem>
<MenuItem onClick={handleClose}>20</MenuItem>
<MenuItem onClick={handleClose}>300</MenuItem>
</Menu>
</div>
);
}
Related documentation:
https://developer.mozilla.org/en-US/docs/Web/CSS/justify-content
https://css-tricks.com/snippets/css/a-guide-to-flexbox/
A more flexible solution to your problem,
use <ListItemText> inside <MenuItem>
In this way you can style parts of the element.
<MenuItem onClick={handleClose}>
<ListItemText style={{ paddingRight: 50 }}>undo</ListItemText>
<ListItemText style={{ textAlign: "right" }}>ctrl+z</ListItemText>
</MenuItem>
example : shortcut hint on the right.
You can use this code to align the menu
anchorOrigin={{
vertical: 'bottom',
horizontal: 'center',
}}
transformOrigin={{
vertical: 'bottom',
horizontal: 'center',
}}
Example
<Menu
id="order-menu"
anchorEl={anchorEl}
keepMounted
open={Boolean(anchorEl)}
onClose={() => setAnchorEl(null)}
anchorOrigin={{
vertical: 'bottom',
horizontal: 'center',
}}
transformOrigin={{
vertical: 'bottom',
horizontal: 'center',
}}
style={{top: 170}} // you can set top position so that it will show under the selection
>
{options.map((option, index) => (
<MenuItem
key={option}
selected={index === selectedIndex}
onClick={(event) => handleMenuItemClick(event, index)}
>
{option}
</MenuItem>
))}
mui 5 could use sx.
<MenuItem sx={{ justifyContent: 'flex-end' }}>

Categories

Resources