[英]How to implement Formik's Field component with Material-Ui Autocomplete for Multi-Select check boxes?
[英]Using Material-UI's Autocomplete component with Formik
目前正在尝试将 Material UI 的Autocomplete组件与 Formik 一起使用。 到目前为止,诸如来自 Material-UI 的文本字段和传统选择之类的东西与 Formik 配合得非常好。 实现自动完成并非如此。 Formik 的 onChange 处理程序似乎没有更新我的city_id
的值。 我知道 Autocomplete 仍然不是 Material-UI 的核心库的一部分,但目前仍在观察这样的事情是否可行。
import React from "react";
import ReactDOM from "react-dom";
import { Formik, Form } from 'formik';
import TextField from '@material-ui/core/TextField';
import Autocomplete from '@material-ui/lab/Autocomplete';
import Button from '@material-ui/core/Button';
import { cities } from '../data/cities';
import "./styles.css";
const initialValues = {
city_id: '',
};
const submit = params => {
alert(`Value for city_id is: ${params.city_id}`);
};
function App() {
return (
<Formik
initialValues={ initialValues }
onSubmit={ submit }
>
{({
handleChange,
values,
}) => (
<Form>
<Autocomplete
id="city_id"
name="city_id"
options={ cities }
groupBy={ option => option.state }
getOptionLabel={ option => option.name }
style={{ width: 300 }}
renderInput={params => (
<TextField
{ ...params }
onChange={ handleChange }
margin="normal"
label="Cities"
fullWidth
value={ values.city_id }
/>
)}
/>
<Button
variant="contained"
color="primary"
type="submit"
>
Submit
</Button>
</Form>
)}
</Formik>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
您的问题是handleChange
不会按照您的方式工作。
如果您查看handleChange 文档:
通用输入更改事件处理程序。 这将更新 values[key],其中 key 是事件发射输入的 name 属性。 如果 name 属性不存在,handleChange 将查找输入的 id 属性。 注意:这里的“输入”是指所有 HTML 输入。
这应该可以正常工作,但问题是Autocomplete
中的TextField
只会在您在其上键入handleChange
时触发handleChange
,并且值将是文本,而不是您想要的id
或其他属性,因此您需要将handleChange
移动到Autocomplete
。
还有另一个问题,您不能在Autocomplete
使用handleChange
,因为它没有引用您想要的输入,并且它还具有与input
的正常onChange
不同的参数,如您在文档中所见。
onChange
功能
值更改时触发的回调。
签名:
function(event: object, value: any) => void
event
: 回调的事件源
value
:空
所以你需要做的是使用setFieldValue
并将其传递给Autocomplete
就像
onChange={(e, value) => setFieldValue("city_id", value)}
您需要传递您的字段名称以及您想要获取的值。
这是一个工作示例
@vencovsky 提供了正确的答案,该答案仍然适用于 Material UI 14.10.1。
我正在添加更多内容,因为我在使用Yup
验证时将我的字段设置为required
。
为了Yup
正常工作,我有以下内容:是的配置:
validationSchema = {
Yup.object().shape({
contact: Yup.string().max(255).required('Contact is required'),
})
}
反应:
<Autocomplete
id="contact-autocomplete"
options={contacts}
getOptionLabel={(contact) => `${contact?.firstName} ${contact?.lastName}`}
onChange={(e, value) => setFieldValue("contact", value?.id || "")}
onOpen={handleBlur}
includeInputInList
renderInput={(params) => (
<TextField
{...params}
error={Boolean(touched.contact && errors.contact)}
fullWidth
helperText={touched.contact && errors.contact}
label="Contact Person"
name="contact"
variant="outlined"
/>
)}
/>
当用户单击Autocomplete
元素时,它会触发onOpen
运行Formik
onBlur
并将该字段标记为已触摸。 如果随后未选取项目,Formik 会flags
该字段并显示Contact is required
验证消息。
您必须在Autocomplete
标记中添加onChange = {(event, value) => handleChange(value)}
作为
import React from "react";
import ReactDOM from "react-dom";
import { Formik, Form } from 'formik';
import TextField from '@material-ui/core/TextField';
import Autocomplete from '@material-ui/lab/Autocomplete';
import Button from '@material-ui/core/Button';
import { cities } from '../data/cities';
import "./styles.css";
const [cityId,setCityId]=React.useState({city_id:''});
const handleChange=(value)=>{
// Here is the value is a selected option label or the new typed value
setCityId({city_id:value});
}
function App() {
return (
<Formik
initialValues={ cityId }
onSubmit={() => {
alert(`Value for city_id is: ${cityId.city_id}`);
}}
>
{({
handleChange,
values,
}) => (
<Form>
<Autocomplete
id="city_id"
name="city_id"
options={ cities }
groupBy={ option => option.state }
getOptionLabel={ option => option.name }
style={{ width: 300 }}
onChange = {(event, value) => handleChange(value)}
renderInput={params => (
<TextField
{ ...params }
onChange={ handleChange }
margin="normal"
label="Cities"
fullWidth
value={ values.city_id }
/>
)}
/>
<Button
variant="contained"
color="primary"
type="submit"
>
Submit
</Button>
</Form>
)}
</Formik>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
如果 onChange 不起作用,您也可以使用 onInputChange。
我最近遇到了同样的问题并解决了。 分享我的经验
直接在OnChange
方法上更新 formik 值解决了这个问题
onChange={(event, value) => (formik.values.country = value!)}
这是完整的代码
Formik 设置
const formik = useFormik({
initialValues: {
id: user.id || "",
name: user.name || "",
country: user.country,
email: user.email || "",
submit: null,
},
validationSchema: Yup.object({
email: Yup.string()
.email("Must be a valid email")
.max(255)
.required("Email is required"),
name: Yup.string().max(255).required("Name is required"),
}),
onSubmit: async (values, helpers): Promise<void> => {
console.log("Updating user...");
try {
let userData: UserDetails = {
id: values.id,
email: values.email,
name: values.name,
country: values.country,
};
await userApi.registerUser(userData);
helpers.setStatus({ success: true });
helpers.setSubmitting(false);
toast.success("User updated!");
} catch (err) {
console.error(err);
toast.error("Something went wrong!");
helpers.setStatus({ success: false });
helpers.setErrors({ submit: err.message });
helpers.setSubmitting(false);
}
},
});
自动完成
<Autocomplete
getOptionLabel={(option): string => option.text}
options={countries}
value={formik.values.country}
defaultValue={formik.values.country}
onChange={(event, value) => (formik.values.country = value!)}
renderInput={(params): JSX.Element => (
<TextField
{...params}
fullWidth
label="Country"
name="country"
error={Boolean(
formik.touched.country && formik.errors.country
)}
helperText={formik.touched.country && formik.errors.country}
onBlur={formik.handleBlur}
/>
)}
/>
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.