Prevent to open dialog modal in loop - reactjs

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>
)
})}

Related

Material UI Dialog with checkbox acknowledgement before user can press the yes button to delete record

I am trying to implement a mui dialog box that contains a checkbox that the user has to check/acknowledge first before they can select the "Yes" option.
I currently have a working dialog box component that I am calling that doesn't have the checkbox, but I have added the checkbox part as follows:
export default function ConfirmCheckboxDialog(props) {
const { confirmDialog, setConfirmDialog } = props;
const classes = useStyles();
const [checked, setChecked] = React.useState(false);
const handleChange = (event) => {
setChecked(event.target.checked);
};
return (
<Dialog open={confirmDialog.isOpen} classes={{ paper: classes.dialog }}>
<DialogTitle className={classes.dialogTitle}>
<IconButton disableRipple className={classes.titleIcon} size="large">
<NotListedLocationIcon />
</IconButton>
</DialogTitle>
<DialogContent className={classes.dialogContent}>
<DialogContentText id="alert-dialog-description">
<Typography variant="h6">{confirmDialog.title}</Typography>
<FormControlLabel
control={
<Checkbox checked={checked} onChange={handleChange} />
}
label="Please acknowledge"
/>
</DialogContentText>
</DialogContent>
<DialogActions className={classes.dialogAction}>
<Controls.Button
text="No"
color="primary"
onClick={() => setConfirmDialog({ ...confirmDialog, isOpen: false })}
/>
<Controls.Button text="Yes" color="success" onClick={confirmDialog.onConfirm} />
</DialogActions>
</Dialog>
);
}
Now I am calling this ConfirmCheckboxDialog component above from another component where I have set the following details:
const [confirmDialog, setConfirmDialog] = useState({ isOpen: false, title: '' });
I also have the following button:
<Button
color="secondary"
onClick={() => {
setConfirmDialog({
isOpen: true,
title: `Delete?`,
onConfirm: () => {
console.log("Deleted......";
}
});
>
{<span>Delete</span>}
</Button>
<ConfirmCheckboxDialog confirmDialog={confirmDialog} setConfirmDialog={setConfirmDialog} />
Based on the above ConfirmCheckboxDialog component, I'm not sure how to validate the checkbox against the Yes button as the only means of the onClick={confirmDialog.onConfirm} /> being set is if the checkbox is set/true
Any help would be good.
Try to define a dedicate function to handle the Yes button click:
const handleYes = () => {
if (checked && confirmDialog.onConfirm) {
setConfirmDialog({ ...confirmDialog, isOpen: false })
confirmDialog.onConfirm();
}
}
...
<Controls.Button text="Yes" color="success" onClick={() => handleYes()} />

Open a modal (or dialogue) from a dropdown asking the user if they would like to take an action

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>
);
}

'Save Palette' button gives a TypeError of 'savePalette' is not a function

My 'NewPaletteForm' is a functional component as I've used react hooks.
So when I click the button 'Save Palette', an error occurs which says 'props.savePalette is not a function'.
ERROR:-
TypeError: props.savePalette is not a function
Code:
'App.js':
class App extends Component {
constructor(props) {
super(props);
this.state = { palettes: seedColors };
this.findPalette = this.findPalette.bind(this);
this.savePalette = this.savePalette.bind(this);
}
findPalette(id) {
return this.state.palettes.find(function (palette) {
return palette.id === id;
});
}
savePalette(newPalette) {
this.setState({ palettes: [...this.state.palettes, newPalette] });
}
render() {
return (
<Switch>
<Route
exact
path='/palette/new'
render={(routeProps) => <NewPaletteForm savePalette={this.savePalette} {...routeProps} />} />
'NewPaletteForm.js' : Functional Component which includes react hooks
function NewPaletteForm() {
const classes = useStyles();
const [open, setOpen] = useState(false);
const [currentColor, setCurrentColor] = useState('teal');
const [colors, setColors] = useState([{ color: 'pink', name: 'pink' }]);
const [newName, setNewName] = useState('');
useEffect(() => {
ValidatorForm.addValidationRule('isColorNameUnique', (value) => {
return colors.every(
({ name }) => name.toLowerCase() !== value.toLowerCase()
);
});
ValidatorForm.addValidationRule('isColorUnique', (value) => {
return colors.every(
({ color }) => color !== currentColor
);
});
})
const handleDrawerOpen = () => {
setOpen(true);
};
const handleDrawerClose = () => {
setOpen(false);
};
function updateCurrentColor(newColor) {
setCurrentColor(newColor.hex);
};
function addNewColor() {
const newColor = {
color: currentColor,
name: newName
}
setColors(oldColors => [...oldColors, newColor]);
setNewName('');
};
function handleChange(evt) {
setNewName(evt.target.value);
}
function handleSubmit(props) {
const newPalette = {
paletteName: 'Test Palette',
colors: colors
}
props.savePalette(newPalette);
props.history.push('/');
}
return (
<div className={classes.root}>
<CssBaseline />
<AppBar
position="fixed"
color='default'
className={clsx(classes.appBar, {
[classes.appBarShift]: open,
})}
>
<Toolbar>
<IconButton
color="inherit"
aria-label="open drawer"
onClick={handleDrawerOpen}
edge="start"
className={clsx(classes.menuButton, open && classes.hide)}
>
<MenuIcon />
</IconButton>
<Typography variant="h6" noWrap>
Persistent drawer
</Typography>
<Button variant='contained' color='primary' onClick={handleSubmit}>Save Palette</Button>
</Toolbar>
</AppBar>
<Drawer
className={classes.drawer}
variant="persistent"
anchor="left"
open={open}
classes={{
paper: classes.drawerPaper,
}}
>
<div className={classes.drawerHeader}>
<IconButton onClick={handleDrawerClose}>
<ChevronLeftIcon />
</IconButton>
</div>
<Typography variant='h4'>Design Your Palette</Typography>
<div>
<Button variant="contained" color="secondary">
Clear Palette
</Button>
<Button variant="contained" color="primary">
Random Color
</Button>
</div>
<Divider />
<ChromePicker color={currentColor} onChangeComplete={updateCurrentColor} />
<ValidatorForm onSubmit={addNewColor}>
<TextValidator
value={newName}
onChange={handleChange}
validators={['required', 'isColorNameUnique', 'isColorUnique']}
errorMessages={['Enter a color name', 'Color name must be unique', 'Color already used!']}
/>
<Button
variant='contained'
type='submit'
color='primary'
style={{
backgroundColor: currentColor
}}
>
Add Color
</Button>
</ValidatorForm>
</Drawer>
<main
className={clsx(classes.content, {
[classes.contentShift]: open,
})}
>
<div className={classes.drawerHeader} />
{colors.map(color => (
<DraggableColorBox color={color.color} name={color.name} />
))}
</main>
</div>
);
}
Button in the NewPaletteForm Component: (Used Material UI Button component)
<Button variant='contained' color='primary' onClick={handleSubmit}>Save Palette</Button>
You should remove props from function argument. because you are calling handleSubmit on button click so it's getting event as props.
function handleSubmit() {
const newPalette = {
paletteName: 'Test Palette',
color: colors
}
props.savePalette(newPalette);
props.history.push('/');
}
Also add props argument to function NewPaletteForm(props) {

My handler does not set the state - Material UI

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>
</>
);
}

Material UI Tooltip Stays Open after triggered Dialog is closed

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/

Resources