簡體   English   中英

如何使用 Material-Ui 自動完成多選復選框實現 Formik 的 Field 組件?

[英]How to implement Formik's Field component with Material-Ui Autocomplete for Multi-Select check boxes?

我正在嘗試使用復選框為多個值實現 Formik 的 Field 組件和 Material-Ui 自動完成功能。 每次我嘗試 select 下拉列表中的一個值時,它都會關閉彈出窗口,我必須再次打開它以進行下一個值選擇。 由於自動完成的 onChange 行為,我正在使用 setFieldValue() 方法來更新字段值。

import React, { useState, useEffect } from "react";
import { ErrorMessage, useField, Field, useFormikContext } from "formik";
import styles from "./Form.module.scss";
import { makeStyles, TextField, Checkbox } from "@material-ui/core";
import { Autocomplete } from "@material-ui/lab";
import service from "http-service";
import CheckBoxOutlineBlankIcon from "@material-ui/icons/CheckBoxOutlineBlank";
import CheckBoxIcon from "@material-ui/icons/CheckBox";

// Interface
interface IProps {
  name: string;
  rest?: any;
  className?: string;
  marginBottom?: string;
  label?: string;
  options?: any[];
  disabled?: boolean;
  tabIndex?: number;
  multiple?: boolean;
  returnArray?: boolean;
  referentialIdKey?: string;
  referentialNameKey?: string;
  serviceConfig?: string;
  query?: string;
  processResponse?: Function;
}

// Custom Style
const useStyles = makeStyles((theme) => ({
  root: {
    "&  .MuiAutocomplete-inputRoot": {
      padding: "6px",
    },
  },
}));

const AsyncSearchMultiSelect: React.FC<IProps> = (props) => {
  const {
    name,
    className,
    disabled,
    options,
    marginBottom,
    label,
    tabIndex,
    multiple,
    returnArray,
    referentialIdKey,
    referentialNameKey,
    serviceConfig,
    query,
    processResponse,
    ...rest
  } = props;

  const { setFieldValue } = useFormikContext();
  const [field] = useField(name);
  const classes = useStyles();

  // States :
  const [asyncOptions, setAsyncOptions] = useState<any[]>([]);
  const [fetchedData, setFetchedData] = useState<any>();

  // all
  const [selectedOpt, setSelectedOpt] = useState<any>([]);

  // API Call for Dropdown Options :
  useEffect(() => {
    if (!serviceConfig) return;
    service[serviceConfig]
      .getDataByQuery(query || "")
      .then(({ data }: { data: any[] }) => {
        let dataSet = processResponse ? processResponse(data) : data;
        if (dataSet.data) {
          dataSet = dataSet.data;
        }
        setFetchedData(dataSet);
        let tempOptions = dataSet.map((item: any) => {
          return {
            name: referentialNameKey ? item[referentialNameKey] : item["name"],
            value: referentialIdKey ? item[referentialIdKey] : item["id"],
          } as never;
        });
        tempOptions.unshift({ name: "All", value: "all" });
        console.log("tempOptions >>>> ", tempOptions);
        setAsyncOptions(tempOptions);
      })
      .catch((err: any) => console.log("Error! : ", err));
  }, []);

  if (field.value.length > 0 && asyncOptions !== []) {
    let fullObjValues = asyncOptions.filter((option) =>
      field.value.includes(option.value)
    );
    console.log("fullObjValues >>> ", fullObjValues);
    if (fullObjValues.length > 0) {
      setFieldValue(name, fullObjValues);
    }
  }

  const handleChange = (event: any, newValue: any) => {
    console.log("AsyncSearchableEvent (value) >>> ", newValue);
    setFieldValue(name, newValue);
  };

  const getOptionLabelCustom = (option: any) => {
    if (typeof option != "object") {
      let optionTitle: any = asyncOptions.find(
        (element: { value: any }) => element?.value == option
      );
      return optionTitle?.name;
    } else {
      return option?.name;
    }
  };

  const icon = <CheckBoxOutlineBlankIcon fontSize="small" />;
  const checkedIcon = <CheckBoxIcon fontSize="small" />;

  const getComponent = () => {
    return (
      <Autocomplete
        // {...field}
        disableCloseOnSelect
        multiple
        options={options ? options : asyncOptions}
        value={field.value}
        limitTags={2}
        getOptionLabel={(option) => getOptionLabelCustom(option)}
        onChange={(event, value) => handleChange(event, value)}
        renderOption={(option, { selected }) => {
          // 'all' option
          const selectOptIndex = selectedOpt.findIndex(
            (opt: any) => opt.name.toLowerCase() === "all"
          );
          if (selectOptIndex > -1) {
            selected = true;
          }
          //
          return (
            <React.Fragment>
              <Checkbox
                icon={icon}
                checkedIcon={checkedIcon}
                style={{ marginRight: 8 }}
                checked={selected}
              />
              {option.name}
            </React.Fragment>
          );
        }}
        renderInput={(params) => (
          <TextField
            {...params}
            label={label}
            classes={classes}
            fullWidth
            variant="outlined"
          />
        )}
      />
    );
  };

  return (
    <div
      className={styles.element_wrapper}
      style={{ marginBottom: marginBottom }}
    >
      <Field
        {...field}
        id={name}
        name={name}
        disabled={disabled}
        component={getComponent}
        autoComplete="off"
      />
      <div className={styles.error}>
        <ErrorMessage name={name} />
      </div>
    </div>
  );
};

export default AsyncSearchMultiSelect; ```

嘗試用 open 控制它:

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

  <Autocomplete
            disabled={disabled}
            id={name}
            name={name}
            sx={{width: "100%"}}
            open={open}
            onOpen={() => {
                setOpen(true);
            }}
            onClose={() => {
                setOpen(false);
            }}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM