Как я могу создать кнопку для диалогового окна внутри PopperComponent материала UI Labs Autocomplete - PullRequest
0 голосов
/ 01 апреля 2020

У меня есть автозаполнение пользовательского интерфейса материала, который отображает список фишек. Я добавил кнопку внизу PopperComponent, которая при нажатии должна открыть диалоговое окно.

Но автозаполнение не позволяет открывать DialogBox. Но странная часть в том, что если я добавлю 'open' в Autocomplete, это сработает.

Я попытался добавить событие onMouseDown вместо onClick. Также попробовал event.preventDefault (). Ни один из них не работает. Однако onMouseDown определенно вызвал мой слушатель для диалогового окна и изменил его открытое состояние на true, но диалоговое окно не появилось.

Это ссылка на песочницу. Песочница с кодом

Это компонент, который реализует диалоговое окно.

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" }
];

Я застрял в этом в течение последних нескольких дней. Любая помощь очень ценится.

1 Ответ

1 голос
/ 01 апреля 2020

Проблема с вашим кодом заключается в том, что компонент <Dialog/> находится в компоненте PaperComponentCustom, который отключается после выбора опции.

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

Решение сохранить только компонент <ManageTagButton/> в PaperComponentCustom и переместите компонент <Dialog/> на один уровень вверх. Я полагаю, что даже если у вас есть 10 элементов в <List/>, у вас все равно будет только один <Dialog>, вы не сможете открыть 10 диалоговых компонентов одновременно.

Поэтому ваш компонент <AddTagToThread/> должен отображать непосредственно в диалоге, и состояние диалога open и обработчики handleOpen и handleClose должны быть перемещены в компоненте <AddTagToThread/> также

Рабочие коды и поле ЗДЕСЬ , код ниже

Компонент автозаполнения

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;

...