如何使用 Material-Ui Autocomplete for Multi-Select 复选框实现 Formik 的 Field 组件?
Posted
技术标签:
【中文标题】如何使用 Material-Ui Autocomplete for Multi-Select 复选框实现 Formik 的 Field 组件?【英文标题】:How to implement Formik's Field component with Material-Ui Autocomplete for Multi-Select check boxes? 【发布时间】:2022-01-01 17:28:38 【问题描述】:我正在尝试使用复选框实现 Formik 的 Field 组件和 Material-Ui 自动完成多个值。 每次我尝试从下拉列表中选择一个值时,它都会关闭弹出窗口,我必须再次打开它以进行下一个值选择。 由于自动完成的 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; ```
【问题讨论】:
【参考方案1】:尝试用 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);
【讨论】:
以上是关于如何使用 Material-Ui Autocomplete for Multi-Select 复选框实现 Formik 的 Field 组件?的主要内容,如果未能解决你的问题,请参考以下文章
ReactJS + Material-UI:如何使用 Material-UI 的 <DatePicker> 将当前日期设置为默认值?