Search code examples
reactjsmaterial-uidom-events

Prevent event propagation on row click and dialog in material ui


I'm using and I have a table with a button inside. The button opens a Dialog and I need to be able to support clicking on the table row.
The problem is that with Portals (in react) - the events are propagated, so clicking inside the Dialog (that was opened after clicking on the button) - the click event on the table-row will get fired.

This is the row:

<TableRow onClick={rowClick}>
  <TableCell>Content 1</TableCell>
  <TableCell>Row clicked {count} times</TableCell>
  <TableCell>
    <MyDialog />
  </TableCell>
</TableRow>

This is the dialog:

<>
  <IconButton onClick={handleClickOpen}>
    <EditIcon />
  </IconButton>
  <Dialog disableBackdropClick open={open} onClose={handleClose}>
    <DialogTitle>Dialog</DialogTitle>
    <DialogContent>Some content</DialogContent>
    <DialogActions>
      <Button onClick={handleClose}>Cancel</Button>
      <Button onClick={handleClose}>Save</Button>
    </DialogActions>
  </Dialog>
</>

Here is a working example:
https://codesandbox.io/s/dazzling-hofstadter-gzwll

And this is an animated gif that shows the issue:
enter image description here

I know I can set the "rowClick" on each cell (and leave the last cell without it) but this is just an example and I'm looking for a more generic solution.


Solution

  • It took some time to find a proper solution, but the only way to prevent the propagation of the event was to add a "click" function on the dialog itself:

    <>
      <IconButton onClick={handleClickOpen}>
        <EditIcon />
      </IconButton>
      <Dialog
        disableBackdropClick
        open={open}
        onClose={handleClose}
        onClick={handleDialogClick}
      >
        <DialogTitle>Dialog</DialogTitle>
        <DialogContent>Some content</DialogContent>
        <DialogActions>
          <Button onClick={handleClose} color="primary">
            Cancel
          </Button>
          <Button onClick={handleClose} color="primary">
            Save
          </Button>
        </DialogActions>
      </Dialog>
    </>
    

    And have the handleClickDialog function stop the event propagation:

    const handleDialogClick = e => {
      e.stopPropagation();
    }; 
    

    Here is a working example:
    https://codesandbox.io/s/cocky-violet-19uvd