【问题标题】:How can I create a button to a dialog box inside the PopperComponent of Material UI Labs Autocomplete如何在 Material UI Lab Autocomplete 的 Popper 组件内创建一个对话框按钮
【发布时间】:2020-04-01 03:47:00
【问题描述】:

我有一个 Material UI 自动完成功能,它可以呈现芯片列表。我在 PopperComponent 的底部添加了一个按钮,单击该按钮应打开一个对话框。

但自动完成功能不允许打开对话框。但奇怪的是,如果我在自动完成中添加“打开”,它就可以工作。

我尝试添加 onMouseDown 事件而不是 onClick。另外,尝试了 event.preventDefault()。它们都不起作用。但是 onMouseDown 确实为对话框调用了我的侦听器并将其打开状态更改为 true,但对话框没有出现。

这是沙盒的链接。 Sandbox to the code

这是实现对话框的组件。

import React, { useState } from "react";
import { withStyles } from "@material-ui/core/styles";
import Button from "@material-ui/core/Button";
import Dialog from "@material-ui/core/Dialog";
import MuiDialogTitle from "@material-ui/core/DialogTitle";
import MuiDialogContent from "@material-ui/core/DialogContent";
import MuiDialogActions from "@material-ui/core/DialogActions";
import IconButton from "@material-ui/core/IconButton";
import CloseIcon from "@material-ui/icons/Close";
import Typography from "@material-ui/core/Typography";
import { orange } from "@material-ui/core/colors";

const styles = theme => ({
  form: {
    display: "flex",
    flexDirection: "column",
    margin: "auto",
    width: "fit-content"
  },
  formControl: {
    marginTop: theme.spacing(2),
    minWidth: 120
  },
  formControlLabel: {
    marginTop: theme.spacing(1)
  },
  closeButton: {
    position: "absolute",
    right: theme.spacing(1),
    top: theme.spacing(1),
    color: theme.palette.grey[500]
  },
  selectEmpty: {
    marginTop: theme.spacing(2)
  },
  floatingLabelFocusStyle: {
    color: "green"
  },
  separator: {
    marginTop: theme.spacing(1)
  },
  menuStyle: {
    border: "1px solid black",
    borderRadius: "5%",
    backgroundColor: "lightgrey"
  }
});

const DialogTitle = withStyles(styles)(props => {
  const { children, classes, onClose, ...other } = props;
  return (
    <MuiDialogTitle disableTypography className={classes.root} {...other}>
      <Typography variant="h6">{children}</Typography>
      {onClose ? (
        <IconButton
          aria-label="close"
          className={classes.closeButton}
          onClick={onClose}
        >
          <CloseIcon />
        </IconButton>
      ) : null}{" "}
    </MuiDialogTitle>
  );
});

const DialogContent = withStyles(theme => ({
  root: {
    padding: theme.spacing(2)
  }
}))(MuiDialogContent);

const DialogActions = withStyles(theme => ({
  root: {
    margin: 0,
    padding: theme.spacing(1)
  }
}))(MuiDialogActions);

const ActionButton = withStyles(theme => ({
  root: {
    color: "#E87424",
    backgroundColor: "white",
    "&:hover": {
      backgroundColor: orange[100]
    }
  }
}))(Button);

const ManageTagButton = withStyles(theme => ({
  root: {
    color: "#E87424"
  }
}))(Button);

const TagContainer = props => {
  const [open, setOpen] = useState(false);

  const handleClickOpen = () => {
    console.log("Dialog box clicked");
    setOpen(true);
  };
  const handleClose = () => {
    setOpen(false);
  };

  return (
    <div>
      <ManageTagButton
        onMouseDown={event => {
          event.preventDefault();
          handleClickOpen();
        }}
        size="small"
      >
        MANAGE TAGS
      </ManageTagButton>

      <Dialog
        fullWidth
        maxWidth={"sm"}
        onClose={handleClose}
        aria-labelledby="customized-dialog-title"
        open={open}
      >
        <DialogTitle id="customized-dialog-title">Manage Tags</DialogTitle>
        <DialogContent dividers>
          <h1>
            This is the component of the dialog box. In reality I neeed to
            display a data table with CRUD operations to add more tags.
          </h1>
        </DialogContent>
        <DialogActions>
          <ActionButton autoFocus onClick={handleClose} color="secondary">
            CLOSE
          </ActionButton>
        </DialogActions>
      </Dialog>
    </div>
  );
};

export default TagContainer;

这是实现自动完成的组件。

import React, { Fragment } from "react";
import Chip from "@material-ui/core/Chip";
import Autocomplete from "@material-ui/lab/Autocomplete";
import { withStyles } from "@material-ui/core/styles";
import { makeStyles } from "@material-ui/core/styles";
import TextField from "@material-ui/core/TextField";
import Button from "@material-ui/core/Button";
import List from "@material-ui/core/List";
import ListItem from "@material-ui/core/ListItem";
import ListItemText from "@material-ui/core/ListItemText";
import ListItemSecondaryAction from "@material-ui/core/ListItemSecondaryAction";
import Paper from "@material-ui/core/Paper";
import TagContainer from "./TagContainer";

const ListItemCustom = withStyles(theme => ({
  gutters: {
    paddingLeft: 0,
    paddingRight: 0
  },
  secondaryAction: {
    paddingRight: 0
  }
}))(ListItem);

const AutocompleteCustom = withStyles(theme => ({
  endAdornment: {
    display: "none"
  }
}))(Autocomplete);

const CreateButton = withStyles(theme => ({
  root: {
    color: "#E87424"
  }
}))(Button);

const MuiFilledInputCustom = makeStyles(
  {
    underline: {
      "&&&:before": {
        borderBottom: "none"
      },
      "&&:after": {
        borderBottom: "none"
      }
    }
  },
  { name: "MuiFilledInput" }
);

const loadCustomStyles = () => {
  MuiFilledInputCustom();
};

export default function AddTagToThread() {
  loadCustomStyles();

  const handleSubmit = () => {
    console.log("Add tags to thread");
  };

  const useStyles = makeStyles({
    root: {
      minWidth: 300,
      width: 300,
      height: 250,
      minHeight: 250,
      zIndex: 1
    },
    buttons: {
      display: "flex",
      justifyContent: "flex-end"
    }
  });
  const PaperComponentCustom = options => {
    const classes = useStyles();
    const { containerProps, children } = options;

    return (
      <Paper className={classes.root} {...containerProps} square>
        {children}
        <div className={classes.buttons}>
          <TagContainer />
        </div>
      </Paper>
    );
  };

  return (
    <List dense={false}>
      <ListItemCustom>
        <ListItemText>
          <AutocompleteCustom
            multiple
            id="size-small-filled-multi"
            size="medium"
            options={tagList}
            noOptionsText="No options"
            freeSolo
            filterSelectedOptions
            PaperComponent={PaperComponentCustom}
            getOptionLabel={option => option.name}
            onChange={(event, value) => {
              console.log(value);
            }}
            renderTags={(value, getTagProps) =>
              value.map((option, index) => (
                <Chip
                  variant="default"
                  style={{
                    backgroundColor: option.color
                  }}
                  label={option.name}
                  size="medium"
                  {...getTagProps({ index })}
                />
              ))
            }
            renderOption={option => (
              <Fragment>
                <Chip
                  variant="default"
                  style={{
                    backgroundColor: option.color,
                    padding: "15px",
                    marginLeft: "12px"
                  }}
                  label={option.name}
                  size="medium"
                />
              </Fragment>
            )}
            renderInput={params => (
              <TextField
                {...params}
                variant="filled"
                label="Filter By Tag"
                placeholder="Select Tag"
              />
            )}
          />
        </ListItemText>
        <ListItemSecondaryAction>
          <CreateButton onClick={handleSubmit}>ADD TAG</CreateButton>
        </ListItemSecondaryAction>
      </ListItemCustom>
    </List>
  );
}

const tagList = [
  { name: "Follow Up", tagId: 1, color: "#FFC107" },
  { name: "Important", tagId: 2, color: "#46B978" },
  { name: "Idea", tagId: 3, color: "#EEA5F6" },
  { name: "Non Issue", tagId: 4, color: "#2EACE2" }
];

过去几天我一直被困在这个问题上。任何帮助是极大的赞赏。

【问题讨论】:

  • 我认为这里的问题是 Paper 组件在单击后被卸载,因此实际上没有显示对话框。另外我没有得到以下部分But the weird part is if I add 'open' to Autocomplete it works.你能详细说明一下吗
  • 是的,我想你是对的,popper 在对话框打开之前就被卸载了。但是,如果我通过添加“打开”道具保持我的自动完成弹出器打开,那么它会起作用,因为它会导致纸质组件保持安装状态。
  • 对话框打开时如何防止纸质组件被卸载?
  • 你没有,你只保留按钮和自动完成之外的对话框组件。如果你愿意,我可以修改你的沙盒并向你展示如何
  • 好的,请告诉我怎么做。谢谢

标签: reactjs autocomplete material-ui


【解决方案1】:

您的代码的问题是&lt;Dialog/&gt; 组件位于PaperComponentCustom 组件中,该组件在选择该选项后会被卸载。

<Paper className={classes.root} {...containerProps} square>
    {children}
    <ManageTagButton onMouseDown={handleClickOpen} fullWidth>
       MANAGE TAGS
    </ManageTagButton>
</Paper>

PaperComponentCustom 中仅保留&lt;ManageTagButton/&gt; 组件并将&lt;Dialog/&gt; 组件向上移动一级的解决方案。我想即使 &lt;List/&gt; 中有 10 个元素,你仍然只有一个 &lt;Dialog&gt;,你不能同时打开 10 个对话框组件。

因此,因此您的 &lt;AddTagToThread/&gt; 组件应该直接呈现对话框,并且对话框 open 的状态以及处理程序 handleOpenhandleClose 也应该在 &lt;AddTagToThread/&gt; 组件中移动

工作代码框HERE,代码如下

自动完成组件

import React, { Fragment, useState } from "react";
import Chip from "@material-ui/core/Chip";
import Autocomplete from "@material-ui/lab/Autocomplete";
import { withStyles } from "@material-ui/core/styles";
import { makeStyles } from "@material-ui/core/styles";
import TextField from "@material-ui/core/TextField";
import Button from "@material-ui/core/Button";
import List from "@material-ui/core/List";
import ListItem from "@material-ui/core/ListItem";
import ListItemText from "@material-ui/core/ListItemText";
import ListItemSecondaryAction from "@material-ui/core/ListItemSecondaryAction";
import Paper from "@material-ui/core/Paper";
import TagContainer from "./TagContainer";

const ListItemCustom = withStyles(theme => ({
  gutters: {
    paddingLeft: 0,
    paddingRight: 0
  },
  secondaryAction: {
    paddingRight: 0
  }
}))(ListItem);

const AutocompleteCustom = withStyles(theme => ({
  endAdornment: {
    display: "none"
  }
}))(Autocomplete);

const CreateButton = withStyles(theme => ({
  root: {
    color: "#E87424"
  }
}))(Button);

const MuiFilledInputCustom = makeStyles(
  {
    underline: {
      "&&&:before": {
        borderBottom: "none"
      },
      "&&:after": {
        borderBottom: "none"
      }
    }
  },
  { name: "MuiFilledInput" }
);

const loadCustomStyles = () => {
  MuiFilledInputCustom();
};

const ManageTagButton = withStyles(theme => ({
  root: {
    color: "#E87424"
  }
}))(Button);

export default function AddTagToThread() {
  loadCustomStyles();

  const handleSubmit = () => {
    console.log("Add tags to thread");
  };

  const [open, setOpen] = useState(false);

  const handleClickOpen = () => {
    console.log("Dialog box clicked");
    setOpen(true);
  };
  const handleClose = () => {
    setOpen(false);
  };

  const useStyles = makeStyles({
    root: {
      minWidth: 300,
      width: 300,
      height: 250,
      minHeight: 250,
      zIndex: 1
    },
    buttons: {
      display: "flex",
      justifyContent: "flex-end"
    }
  });
  const PaperComponentCustom = options => {
    const classes = useStyles();
    const { containerProps, children } = options;

    return (
      <Paper className={classes.root} {...containerProps} square>
        {children}
        <ManageTagButton onMouseDown={handleClickOpen} fullWidth>
          MANAGE TAGS
        </ManageTagButton>
      </Paper>
    );
  };

  return (
    <>
      <TagContainer open={open} handleClose={handleClose} />
      <List dense={false}>
        <ListItemCustom>
          <ListItemText>
            <AutocompleteCustom
              multiple
              id="size-small-filled-multi"
              size="medium"
              options={tagList}
              noOptionsText="No options"
              freeSolo
              filterSelectedOptions
              PaperComponent={PaperComponentCustom}
              getOptionLabel={option => option.name}
              onChange={(event, value) => {
                console.log(value);
              }}
              renderTags={(value, getTagProps) =>
                value.map((option, index) => (
                  <Chip
                    variant="default"
                    style={{
                      backgroundColor: option.color
                    }}
                    label={option.name}
                    size="medium"
                    {...getTagProps({ index })}
                  />
                ))
              }
              renderOption={option => (
                <Fragment>
                  <Chip
                    variant="default"
                    style={{
                      backgroundColor: option.color,
                      padding: "15px",
                      marginLeft: "12px"
                    }}
                    label={option.name}
                    size="medium"
                  />
                </Fragment>
              )}
              renderInput={params => (
                <TextField
                  {...params}
                  variant="filled"
                  label="Filter By Tag"
                  placeholder="Select Tag"
                />
              )}
            />
          </ListItemText>
          <ListItemSecondaryAction>
            <CreateButton onClick={handleSubmit}>ADD TAG</CreateButton>
          </ListItemSecondaryAction>
        </ListItemCustom>
      </List>
    </>
  );
}

const tagList = [
  { name: "Follow Up", tagId: 1, color: "#FFC107" },
  { name: "Important", tagId: 2, color: "#46B978" },
  { name: "Idea", tagId: 3, color: "#EEA5F6" },
  { name: "Non Issue", tagId: 4, color: "#2EACE2" }
];

对话框组件

import React, { useState } from "react";
import { withStyles } from "@material-ui/core/styles";
import Button from "@material-ui/core/Button";
import Dialog from "@material-ui/core/Dialog";
import MuiDialogTitle from "@material-ui/core/DialogTitle";
import MuiDialogContent from "@material-ui/core/DialogContent";
import MuiDialogActions from "@material-ui/core/DialogActions";
import IconButton from "@material-ui/core/IconButton";
import CloseIcon from "@material-ui/icons/Close";
import Typography from "@material-ui/core/Typography";
import { orange } from "@material-ui/core/colors";

const styles = theme => ({
  form: {
    display: "flex",
    flexDirection: "column",
    margin: "auto",
    width: "fit-content"
  },
  formControl: {
    marginTop: theme.spacing(2),
    minWidth: 120
  },
  formControlLabel: {
    marginTop: theme.spacing(1)
  },
  closeButton: {
    position: "absolute",
    right: theme.spacing(1),
    top: theme.spacing(1),
    color: theme.palette.grey[500]
  },
  selectEmpty: {
    marginTop: theme.spacing(2)
  },
  floatingLabelFocusStyle: {
    color: "green"
  },
  separator: {
    marginTop: theme.spacing(1)
  },
  menuStyle: {
    border: "1px solid black",
    borderRadius: "5%",
    backgroundColor: "lightgrey"
  }
});

const DialogTitle = withStyles(styles)(props => {
  const { children, classes, onClose, ...other } = props;
  return (
    <MuiDialogTitle disableTypography className={classes.root} {...other}>
      <Typography variant="h6">{children}</Typography>
      {onClose ? (
        <IconButton
          aria-label="close"
          className={classes.closeButton}
          onClick={onClose}
        >
          <CloseIcon />
        </IconButton>
      ) : null}{" "}
    </MuiDialogTitle>
  );
});

const DialogContent = withStyles(theme => ({
  root: {
    padding: theme.spacing(2)
  }
}))(MuiDialogContent);

const DialogActions = withStyles(theme => ({
  root: {
    margin: 0,
    padding: theme.spacing(1)
  }
}))(MuiDialogActions);

const ActionButton = withStyles(theme => ({
  root: {
    color: "#E87424",
    backgroundColor: "white",
    "&:hover": {
      backgroundColor: orange[100]
    }
  }
}))(Button);

const TagContainer = ({ open, handleClose }) => {
  return (
    <Dialog
      fullWidth
      maxWidth={"sm"}
      onClose={handleClose}
      aria-labelledby="customized-dialog-title"
      open={open}
    >
      <DialogTitle id="customized-dialog-title">Manage Tags</DialogTitle>
      <DialogContent dividers>
        <h1>
          This is the component of the dialog box. In reality I neeed to display
          a data table with CRUD operations to add more tags.
        </h1>
      </DialogContent>
      <DialogActions>
        <ActionButton autoFocus onClick={handleClose} color="secondary">
          CLOSE
        </ActionButton>
      </DialogActions>
    </Dialog>
  );
};

export default TagContainer;

【讨论】:

  • 感谢@Sabbin 的帮助。你拯救了我的一天! :-)
猜你喜欢
  • 2020-06-22
  • 2021-06-01
  • 1970-01-01
  • 1970-01-01
  • 2020-12-27
  • 2020-04-07
  • 2021-05-25
  • 2018-08-01
  • 2021-08-01
相关资源
最近更新 更多