Close submenu when clicked on other submenu - reactjs

I am using antd menu and submenu. and i am unable to close the submenu when other sumbenu is opened. I am using react js for the code.I am able to close main menu on other menu expansion. but have no idea how to close submenu on other submenu expansion. Here is my code
<Menu
style={{ width: 220 }}
mode="inline"
openKeys={openKeys}
onOpenChange={onOpenChange}
selectedKeys={[location.pathname]}
title="Navigation"
className="custom-menu"
>
{navigationConfig.map((menu) => {
return (
<>
{menu.submenu.length > 0 ? (
<SubMenu
icon={menu.icon ? <Icon type={menu?.icon} /> : null}
key={menu.key}
title={menu.title}
>
{menu.submenu.map((submenu) => {
return (
<Menu.Item
key={submenu.key}
onClick={submenu.onclick}
>
{submenu.icon ? (
<Icon type={submenu?.icon} />
) : null}
{submenu.title}
{submenu.path ? (
<Link
to={{
pathname: submenu.path,
state: history.location.state,
}}
onClick={() => {
setHeaderTitle(
menu.hasOwnProperty("aliasTitle")
? menu.aliasTitle
: menu.title
);
}}
/>
) : null}
</Menu.Item>
);
})}
</SubMenu>
</Menu.Item>
)}
</>
);
})}
</Menu>

Related

React Menu is closing on element click

I have a menu which applies filter to my list and when I click on an element inside the menu is closing and I can not set more filters. I should click the stepper or the selection box many times and the menu should close on click on submit or cancel and not on click of stepper or selection box
`
<Menu matchWidth={true} isOpen={isOpen} onOpen={handleOpen} onClose={handleCancel} closeOnBlur={false} closeOnSelect={false} >
<ChakraSelectButton headline={'Who?'} information={information} />
<MenuList p={4} onClick={e => e.stopPropagation()} >
<VStack
alignItems={'flex-start'}
// #ts-ignore
ref={ref}
<Stepper
title={'How many people?'}
handleChange={handleChange}
name={people}
value={numberOfPeople ? numberOfPeople : 0}
boxSize={10}
/>
{numberOfPeople > 0 && (
<VStack w={'100%'} onClick={e => e.preventDefault()}>
<Text
alignSelf={'flex-start'}
Please insert the age!
</Text>
{Array.from(Array(numberOfPeople)).map((a, idx) => {
return (
<Select
key={idx}
userSelect={'none'}>
<option value={24}>24</option>
<option value={25}>25</option>
<option value={26}>26</option>
<option value={27}>27</option>
</Select>
);
})}
</VStack>
)}
<Stepper
title={'Pets'}
handleChange={handleChange}
value={numberOfPets ? numberOfPets : 0}
boxSize={10}
/>
<Divider />
<CtaFilterButtons
size={'sm'}
handleCancel={handleCancel}
handleFilterChange={handleSubmit}
/>
</VStack>
</MenuList>
</Menu>
`
I only want to close the menu when I click on submit.

Cannot read property map of undefined react

I'm trying to render a component that uses an array of filters to make a list. I pass the array as an argument to the function but it returns an error. The array is not null or undefined because it shows the itens if I log to the console.
Console.log returns:
Here is my code:
const List = (filtrosPorTipo) => {
let filtros = filtrosPorTipo[0]
let valoresDosFiltros = filtrosPorTipo[1]
let lista = (
<List>
{filtros.map((item, index) => {
return (
<>
<ListItem
button
onClick={() => setOpen({ [item]: !open[item] })}
key={item}
>
<ListItemText primary={item} />
{open[item] ? <ExpandLess /> : <ExpandMore />}
</ListItem>
<Collapse in={open[item]} timeout='auto'>
<List component='div' disablePadding>
{valoresDosFiltros[index].map((filtro) => {
return (
<>
<ListItem key={filtro}>
<p>{`${filtro}\n`}</p>
<ListItemSecondaryAction>
<Checkbox
label={filtro}
key={filtro.toString()}
color='primary'
onChange={() => handleChecked(filtro)}
checked={checked[filtro]}
/>
</ListItemSecondaryAction>
</ListItem>
<Divider />
</>
)
})}
</List>
</Collapse>
</>
)
})}
</List>
)
return lista
}
Error:
Perhaps the component it's trying to render before "filtros" is assigned. It's a common and logical behavior in React.
Try adding a conditional before the .map() call:
{filtros ? filtros.map((item, index) => {
return (
<>
<ListItem
button
onClick={() => setOpen({ [item]: !open[item] })}
key={item}
>
<ListItemText primary={item} />
{open[item] ? <ExpandLess /> : <ExpandMore />}
</ListItem>
<Collapse in={open[item]} timeout='auto'>
<List component='div' disablePadding>
{valoresDosFiltros[index].map((filtro) => {
return (
<>
<ListItem key={filtro}>
<p>{`${filtro}\n`}</p>
<ListItemSecondaryAction>
<Checkbox
label={filtro}
key={filtro.toString()}
color='primary'
onChange={() => handleChecked(filtro)}
checked={checked[filtro]}
/>
</ListItemSecondaryAction>
</ListItem>
<Divider />
</>
)
})}
</List>
</Collapse>
</>
)
}) : null}
You can map over the values when they are present like so. If you are not planning on displaying a Loading screen in the process of waiting for the data then this would work. Otherwise use a ternary operator like the other answer.
{filtros && filtros.map((item, index) => {
return (
<>
<ListItem
button
onClick={() => setOpen({ [item]: !open[item] })}
key={item}
>
<ListItemText primary={item} />
{open[item] ? <ExpandLess /> : <ExpandMore />}
</ListItem>
<Collapse in={open[item]} timeout='auto'>
<List component='div' disablePadding>
{valoresDosFiltros[index].map((filtro) => {
return (
<>
<ListItem key={filtro}>
<p>{`${filtro}\n`}</p>
<ListItemSecondaryAction>
<Checkbox
label={filtro}
key={filtro.toString()}
color='primary'
onChange={() => handleChecked(filtro)}
checked={checked[filtro]}
/>
</ListItemSecondaryAction>
</ListItem>
<Divider />
</>
)
})}
</List>
</Collapse>
</>
)
})}
While rendering the component you have to check data in filtrosPorTipo. It has an array value or not. Like below:
const List = (filtrosPorTipo) => {
if (filtrosPorTipo && filtrosPorTipo.length > 0) {
let filtros = filtrosPorTipo[0]
let valoresDosFiltros = filtrosPorTipo[1]
let lista = (
<List>
{filtros.map((item, index) => {
return (
<>
<ListItem
button
onClick={() => setOpen({ [item]: !open[item] })}
key={item}
>
<ListItemText primary={item} />
{open[item] ? <ExpandLess /> : <ExpandMore />}
</ListItem>
<Collapse in={open[item]} timeout='auto'>
<List component='div' disablePadding>
{valoresDosFiltros[index].map((filtro) => {
return (
<>
<ListItem key={filtro}>
<p>{`${filtro}\n`}</p>
<ListItemSecondaryAction>
<Checkbox
label={filtro}
key={filtro.toString()}
color='primary'
onChange={() => handleChecked(filtro)}
checked={checked[filtro]}
/>
</ListItemSecondaryAction>
</ListItem>
<Divider />
</>
)
})}
</List>
</Collapse>
</>
)
})}
</List>
)
return lista
}
return 'No data available!'
}

I want to add a "download button on modal carousel using react-images, the button should be available on modal popup

can i add a button as a parameter to the carousel,i tried all possible ways to add a button to this
<div>
<h2>Using with a Lightbox component</h2>
<Gallery photos={photos} onClick={openLightbox} />
<ModalGateway>
{viewerIsOpen ? (
<Modal onClose={closeLightbox}>
<Carousel
currentIndex={currentImage}
views={photos.map(x => ({
...x,
srcset: x.srcSet,
caption: x.title
}))}
/>
</Modal>
) : null}
</ModalGateway>
<div>
<Down />
</div>
</div>
You can create your own component:
const CustomFooter = ({ isModal, currentView }) => isModal && (
<div className="react-images__footer">
<button
className="btn some-stylin"
type="button"
onClick={() => { downloadImage(currentView.src); }}
>
Download
</button>
</div>
);
<ModalGateway>
{modalIsOpen ? (
<Modal onClose={this.toggleGallery}>
<Carousel
views={this.imgs}
currentIndex={currentIndex}
frameProps={{ autoSize: 'height' }}
components={{ Footer: CustomFooter }}
/>
</Modal>
) : null}
</ModalGateway>

How to fix shadow for menu material-ui

When I use a few icon menus than box-shadow looks very dark. How to fix that?
1:
Codesandbox example https://codesandbox.io/embed/flamboyant-tdd-r83u1
<div>
{items.map((item, index) => {
return (
<Fragment key={index}>
<IconButton
aria-owns={open ? "long-menu" : undefined}
onClick={this.handleClick}
>
<MoreVertIcon />
</IconButton>
<Menu anchorEl={anchorEl} open={open} onClose={this.handleClose}>
{options.map(option => (
<MenuItem key={option} onClick={this.handleClose}>
{option}
</MenuItem>
))}
</Menu>
</Fragment>
);
})}
</div>
Because, actually you are triggering multiple menus with the same flag at the same time. So shadow is dark because there are multiple menus one after the other.
Below code should fix this, You don't have to render Menu in items loop
render() {
const items = [...Array(10).keys()];
const { anchorEl } = this.state;
const open = Boolean(anchorEl);
return (
<div>
{items.map((item, index) => {
return (
<Fragment key={index}>
<IconButton
aria-owns={open ? "long-menu" : undefined}
onClick={this.handleClick}
>
<MoreVertIcon />
</IconButton>
</Fragment>
);
})}
<Menu anchorEl={anchorEl} open={open} onClose={this.handleClose}>
{options.map(option => (
<MenuItem key={option} onClick={this.handleClose}>
{option}
</MenuItem>
))}
</Menu>
</div>
);
}

Material-UI - Click on Menu Button opens all Menu Items available

I'm having a small issue with Material-UI. And it is that everytime I click on a button to open an specific dropdown/menuItem it opens all the Dropdown/Items available in the AppBar. I did change the 'open' variable name, but it just gives me an error instead. The Material-UI documentation does not includes examples two or more dropdown menus.
Here's my code:
class MaterialTest extends Component {
state = {
anchorEl: null
};
handleClick = event => {
this.setState({ anchorEl: event.currentTarget });
};
handleClose = () => {
this.setState({ anchorEl: null });
};
render() {
const { anchorEl } = this.state;
const open = Boolean(anchorEl);
return (
<div style={mainDiv}>
<AppBar position="static" color="default" style={barStyle}>
<Toolbar style={toolStyle}>
<NavLink to="/">
<Button>Home</Button>
</NavLink>
<Button
aria-owns={anchorEl ? 'product-shipping' : null}
aria-haspopup="true"
onClick={this.handleClick}
>
Product Shipping
</Button>
<Menu
id="product-shipping"
anchorEl={anchorEl}
open={open}
onClose={this.handleClose}
>
<NavLink to="viewAll">
<MenuItem onClick={this.handleClose}>View Latest SKUs</MenuItem>
</NavLink>
<NavLink to="addSku">
<MenuItem onClick={this.handleClose}>Add New SKU</MenuItem>
</NavLink>
<MenuItem onClick={this.handleClose}>Import / Export</MenuItem>
<MenuItem onClick={this.handleClose}>Tables</MenuItem>
</Menu>
<Button
aria-owns={anchorEl ? 'inventory' : null}
aria-haspopup="true"
onClick={this.handleClick}
>
Inventory
</Button>
<Menu
id="inventory"
anchorEl={anchorEl}
open={open}
onClose={this.handleClose}
>
<NavLink to="viewInventory">
<MenuItem onClick={this.handleClose}>Site Inventory</MenuItem>
</NavLink>
<MenuItem onClick={this.handleClose}>
Warehouse Inventory
</MenuItem>
<MenuItem onClick={this.handleClose}>Add New Inventory</MenuItem>
</Menu>
<Button
aria-owns={anchorEl ? 'vendor-information' : null}
aria-haspopup="true"
onClick={this.handleClick}
>
Vendor Information
</Button>
</Toolbar>
</AppBar>
</div>
);
}
}
Any Ideas? Thank you
It might be because all the menus are being opened when anchorEl is set. The open prop is only checking for Boolean(anchorEl) and they all share this same state (so whenever it returns true they all open)
You could try setting an anchorEl2, anchorEl3 and so on in the state and change each Menu and Button accordingly.

Resources