[英]Using Material-UI's Autocomplete component with Formik
[英]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.