I am using the component "Dialog" from Material UI.
When I click on the button to close the Dialog (which triggers handleCLose), it does not set the state to false.
I read a similar problem here: OnClick Listeners not working after closing full-screen dialog using react-material-ui
but I have not managed to save it so far.
const Transition = React.forwardRef(function Transition(props, ref) {
return <Slide direction="up" ref={ref} {...props} />;
});
function Information() {
const [open, setOpen] = React.useState(false);
const handleClickOpen = () => {
setOpen(true);
};
const handleClose = () => {
setOpen(false);
console.log(open)
};
return (
<div onClick={()=>handleClickOpen()}>
Information
<Dialog
open={open}
TransitionComponent={Transition}
keepMounted
onClose={handleClose}
aria-labelledby="alert-dialog-slide-title"
aria-describedby="alert-dialog-slide-description"
>
<DialogTitle id="alert-dialog-slide-title">{"Information"}</DialogTitle>
<DialogContent>
<DialogContentText id="alert-dialog-slide-description">
Blablabla
</DialogContentText>
</DialogContent>
<DialogActions>
<Button onClick={handleClose} color="primary"> // The function is here
Close
</Button>
</DialogActions>
</Dialog>
</div>
);
}
export default Information
It looks like you have wrapped your dialog in a div with an onClick function that sets the dialog to open. What is happening is that onClick is being called whenever you click inside the dialog. So even when you click the close button it is calling handleClickOpen. Try separating them:
return (
<> // Add wrapping fragment
<div onClick={()=>handleClickOpen()}>
Information
</div> // close div here
<Dialog
open={open}
TransitionComponent={Transition}
keepMounted
onClose={handleClose}
aria-labelledby="alert-dialog-slide-title"
aria-describedby="alert-dialog-slide-description"
>
<DialogTitle id="alert-dialog-slide-title">{"Information"}</DialogTitle>
<DialogContent>
<DialogContentText id="alert-dialog-slide-description">
Blablabla
</DialogContentText>
</DialogContent>
<DialogActions>
<Button onClick={handleClose} color="primary">
Close
</Button>
</DialogActions>
</Dialog>
</>
);
}
Related
I would like to open a modal (or dialogue) when a user selects an option from a dropdown menu.
Eventually there will be a few options in the dropdown, and different dialogues/modals will be called and rendered depending on which dropdown option has been clicked. For now - how do I get the modal/dialogue to open with dropdown menu events?
I'm currently using the handleClose handler to attempt to open a dialogue since that event should be easy to grab and use right out of the docs for MUI Menu and MenuItem.
The origination call to the DropdownMenu component (which works well and shows the dropdown menu) occurs in a table through the click of an icon
<DropdownMenu options={['Show modal or dialogue to the user']}>
<MoreHorizIcon />
</DropdownMenu>
The DropdownMenu component (also working well itself, except for not triggering the dialogue/modal) looks like this
interface IProps extends Omit<unknown, 'children'> {
children: any;
options: string[];
}
const ITEM_HEIGHT = 48;
const DropdownMenu = ({ children, options }: IProps) => {
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
const open = Boolean(anchorEl);
const handleClick = (event: React.MouseEvent<HTMLElement>) => {
setAnchorEl(event.currentTarget);
};
const showModal = () => {
return (
<AlertDialog />
)
}
const handleClose = () => {
//the native alert dialogue works well
alert('I want to show a dialog or modal the same way this alert shows up and ask the user if they are sure they want to delete something')
//why isn't the custom alert dialog being called?
showModal();
setAnchorEl(null);
};
return (
<div>
<IconButton
aria-label="more"
id="more-button"
aria-controls="long-menu"
aria-expanded={open ? 'true' : undefined}
aria-haspopup="true"
onClick={handleClick}
>
{children}
</IconButton>
<Menu
id="dropdownmenu"
MenuListProps={{
'aria-labelledby': 'more-button'
}}
anchorEl={anchorEl}
open={open}
onClose={handleClose}
PaperProps={{
style: {
maxHeight: ITEM_HEIGHT * 4.5,
width: '20ch'
}
}}
>
{options.map(option => (
<MenuItem key={option} onClick={handleClose} >
{option}
</MenuItem>
))}
</Menu>
</div>
);
};
export default DropdownMenu;
And the example starter dialogue I am using to get the ball rolling looks like this
const AlertDialog = () => {
const [open, setOpen] = React.useState(true);
const handleClose = () => {
setOpen(false);
};
return (
<div>
<Dialog
open={open}
onClose={handleClose}
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
>
<DialogTitle id="alert-dialog-title">
{"Sweet Filler Dialog"}
</DialogTitle>
<DialogContent>
<DialogContentText id="alert-dialog-description">
Are you sure?
</DialogContentText>
</DialogContent>
<DialogActions>
<Button onClick={handleClose}>NO</Button>
<Button onClick={handleClose} autoFocus>
YES
</Button>
</DialogActions>
</Dialog>
</div>
);
}
You can use a state variable to trigger the modal in the DropdownMenu component, whenever you wanted to show the dialog/modal.
const [isModalOpen, setIsModalOpen] = React.useState(false);
and then in the handleClose, you can update the modal state to open the modal.
const handleClose = () => {
setIsModalOpen(true)
setAnchorEl(null);
};
Then somewhere in your JSX of DropdownMenu, you can conditionally render the AlertDialog component like this
{isModalOpen ? <AlertDialog open={isModalOpen} setOpen={setIsModalOpen} /> : null}
Finally, update your AlertDialog component to use props to handle the closing of the modal.
const AlertDialog = ({ open, setOpen }) => {
const handleClose = () => {
setOpen(false);
};
return (
<div>
<Dialog
open={open}
onClose={handleClose}
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
>
<DialogTitle id="alert-dialog-title">
{"Sweet Filler Dialog"}
</DialogTitle>
<DialogContent>
<DialogContentText id="alert-dialog-description">
Are you sure?
</DialogContentText>
</DialogContent>
<DialogActions>
<Button onClick={handleClose}>NO</Button>
<Button onClick={handleClose} autoFocus>
YES
</Button>
</DialogActions>
</Dialog>
</div>
);
}
I've got some problem with omit re-render while click button which open Dialog component. Currently I use useState flag which toggle my Dialog component but I must avoid re-rendering because there's expensive operations on big data.
Anyone know approach how to Open Dialog by button Open and Close Dialog by click on Dialog's button Exit.
const Item = () => {
const popupRef = useRef()
const dialog = () => {
return(
<Dialog ref={popupRef}
keepMounted
fullWidth
maxWidth="md"
aria-labelledby="alert-dialog-slide-title"
aria-describedby="alert-dialog-slide-description">
<DialogTitle id="alert-dialog-slide-title">
<WrapperDialogHeader>Filters</WrapperDialogHeader>
<WrapperDialogCloseBtn>
<IconButton aria-label="close" >
<CloseIcon />
</IconButton>
</WrapperDialogCloseBtn>
</DialogTitle>
<DialogContent>
Something
</DialogContent>
<DialogActions>
<Button variant="outlined"
// onClick={ What handler here? }
color="primary">
<WrapperDialogOptionBtn>Exit</WrapperDialogOptionBtn>
</Button>
</DialogActions>
</Dialog>
)
}
return(
<>
<IconButton onClick={ /* What method here */ }>
<Typography variant="body1" color="primary">
<FilterListIcon fontSize="small" color="primary"/><WrapperFontSpecialSmall>Filters</WrapperFontSpecialSmall>
</Typography>
</IconButton>
{ dialog() }
</>
Methods like popupRef.current.click() not exist in ES6 I suppose.
How to build mechanism which toggle dialog without re-render whole component Item.
Move the dialog to its own component and wrap in memo()
const Dialog = ({ open, onClose }) => {
return (
<Dialog
keepMounted // why? you said the content is huge, so why keep it mounted
fullWidth
maxWidth="md"
aria-labelledby="alert-dialog-slide-title"
aria-describedby="alert-dialog-slide-description"
open={open}
onClose={onClose}
>
<DialogTitle id="alert-dialog-slide-title">
<WrapperDialogHeader>Filters</WrapperDialogHeader>
<WrapperDialogCloseBtn>
<IconButton aria-label="close" >
<CloseIcon />
</IconButton>
</WrapperDialogCloseBtn>
</DialogTitle>
<DialogContent>
Something
</DialogContent>
<DialogActions>
<Button variant="outlined" onClick={onClose} color="primary">
<WrapperDialogOptionBtn>Exit</WrapperDialogOptionBtn>
</Button>
</DialogActions>
</Dialog>
)
};
export default memo(Dialog); // IMPORTANT
In the Item component,
const Item = () => {
const [dialogOpen, setDialogOpen] = useState(false);
const handleDialogOpen = () => setDialogOpen(true);
// prevent function being recreated on state change
const handleDialogClose = useCallback(() => setDialogOpen(false), []);
return (
<>
<IconButton onClick={handleDialogOpen}>
<Typography variant="body1" color="primary">
<FilterListIcon fontSize="small" color="primary" /><WrapperFontSpecialSmall>Filters</WrapperFontSpecialSmall>
</Typography>
</IconButton>
<Dialog open={dialogOpen} onClose={handleDialogClose} />
</>
);
}
Sidenote, it appears the dialog contains some sort of filter UI, presumably one or more lists. You may want to have a look at react-window if you are going to create long lists.
I'm trying to use material-ui checkbox inside dialog but onChange function seems not working. Please refer the following info for my code:
<Dialog open={showAssetListDialog}>
<DialogTitle id="responsive-dialog-title">
<h3 className="formHeader">Asset List</h3>
<hr />
</DialogTitle>
<DialogContent>
<Typography>
{ availableAssets && Object.keys(assetList).map((key, index) => (
<p>
<Checkbox
const asset_id = {assetList[index].value}
checked = {assetList[index].asset_id}
color = "primary"
onChange = {props.handleCheckboxChange('asset_id')}
onCheck = {props.handleCheckboxChange}
>
</Checkbox>
{assetList[index].label}
</p>
))}
</Typography>
</DialogContent>
<DialogActions>
<Button
color="success"
className="btnSave"
onClick={props.handleAssetListClose}
>
Done
</Button>
</DialogActions>
</Dialog>
I am implemented dialog in loop So How can I prevent to open dialog from loop. Because when I open modal popup then it will open multiple popup.
handleClickOpen = name => event => {
this.setState({
open: true
});
};
handleClose = () => {
this.setState({ open: false });
};
{Developertasklist.map((task, index) => {
return (
<div className={classes.width5}>
<NotesIcon
className={classes.icon}
onClick={this.handleClickOpen()}
/>
<Dialog
onClose={this.handleClose}
aria-labelledby="customized-dialog-title"
open={this.state.open}
>
<DialogTitle
id="customized-dialog-title"
onClose={this.handleClose}
>
Notes
</DialogTitle>
<DialogContent>
<Note />
</DialogContent>
</Dialog>
</div>
)
})}
How to prevent to open popup in loop.
Thanks.
Problem is you are using same state for all task, you could set openTask in state and send open = this.state.openTask === task so that only one task dialog will open.
handleClickOpen = task => event => {
this.setState({
openTask: task
});
};
handleClose = () => {
this.setState({ open: false });
};
{Developertasklist.map((task, index) => {
return (
<div className={classes.width5}>
<NotesIcon
className={classes.icon}
onClick={this.handleClickOpen(taks)}
/>
<Dialog
onClose={this.handleClose}
aria-labelledby="customized-dialog-title"
open={this.state.openTask === task }
>
<DialogTitle
id="customized-dialog-title"
onClose={this.handleClose}
>
Notes
</DialogTitle>
<DialogContent>
<Note />
</DialogContent>
</Dialog>
</div>
)
})}
My assumption is the state of the Dialog is causing the issue, but I have not been able to figure this out. The Tooltip works as intended until the IconButton is clicked. The Dialog pops up as it should but when the dialog is exited, the Tooltip pops up as active.
class DeleteDocument extends React.Component {
state = {
open: false,
};
onDeleteFile() {
try {
ensureJobIsUnlocked();
} catch (err) {
return;
}
const confirmedByUser = true;
if (confirmedByUser) {
this.props.onDeleteFile(this.props.selectedDocument.id);
this.setState({ open: false });
}
}
handleClickOpen = () => {
this.setState({ open: true });
};
handleClose = () => {
this.setState({ open: false });
};
render() {
return (
<div>
<Tooltip id="tooltip-icon" title="Delete Document">
<div>
<IconButton
disabled={(this.props.selectedDocument == null)}
onClick={this.handleClickOpen}
>
<DeleteIcon />
</IconButton>
</div>
</Tooltip>
<Dialog
open={this.state.open}
onClose={this.handleClose}
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
>
<DialogTitle id="alert-dialog-title">{'Delete Document'}</DialogTitle>
<DialogContent>
<DialogContentText id="alert-dialog-description">
This will delete the currently active PDF/Component Design. Are you sure you want to do this?
</DialogContentText>
</DialogContent>
<DialogActions>
<Button onClick={this.handleClose} color="primary">
Cancel
</Button>
<Button onClick={this.onDeleteFile.bind(this)} color="primary" autoFocus>
Delete
</Button>
</DialogActions>
</Dialog>
</div>
);
}
}
See issue #9624:
This is the expected behavior. It's done for accessibility considerations. You have two options, either disable the tooltip response to focus events or disable the dialog restore focus behavior.
1. Disable the tooltip response to focus events (docs)
<Tooltip disableTriggerFocus={true} />
2. Disable the dialog restore focus behavior (docs)
<Dialog disableRestoreFocus={true} />
set disableFocusListener={true} according to this doc https://material-ui.com/api/tooltip/