[英]Using Material-UI's Autocomplete component with Formik
Currently trying to use Material UI's Autocomplete component with Formik.目前正在尝试将 Material UI 的Autocomplete组件与 Formik 一起使用。 So far things like text fields and traditional selects from Material-UI play very nice with Formik.
到目前为止,诸如来自 Material-UI 的文本字段和传统选择之类的东西与 Formik 配合得非常好。 Implementing Autocomplete is not the case.
实现自动完成并非如此。 Formik's onChange handler doesn't seem to update the value for my
city_id
. Formik 的 onChange 处理程序似乎没有更新我的
city_id
的值。 I know Autocomplete is still not apart of Material-UI's core library but was still seeing if something like this was a possibility at the moment.我知道 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);
Your problem is that handleChange
won't work the way you are doing.您的问题是
handleChange
不会按照您的方式工作。
If you take a look at the handleChange docs :如果您查看handleChange 文档:
General input change event handler.
通用输入更改事件处理程序。 This will update the values[key] where key is the event-emitting input's name attribute.
这将更新 values[key],其中 key 是事件发射输入的 name 属性。 If the name attribute is not present, handleChange will look for an input's id attribute.
如果 name 属性不存在,handleChange 将查找输入的 id 属性。 Note: "input" here means all HTML inputs.
注意:这里的“输入”是指所有 HTML 输入。
Which should work fine, but the problem is that the TextField
inside Autocomplete
will only trigger handleChange
when you type something on it, and the value will be the text, not the id
or other property you want, so you need to move handleChange
to the Autocomplete
.这应该可以正常工作,但问题是
Autocomplete
中的TextField
只会在您在其上键入handleChange
时触发handleChange
,并且值将是文本,而不是您想要的id
或其他属性,因此您需要将handleChange
移动到Autocomplete
。
And there is another problem, you can't use handleChange
in the Autocomplete
because it doesn't references the input you want and it also have different parameters from the normal onChange
of the input
, as you can see in the docs .还有另一个问题,您不能在
Autocomplete
使用handleChange
,因为它没有引用您想要的输入,并且它还具有与input
的正常onChange
不同的参数,如您在文档中所见。
onChange
func功能
Callback fired when the value changes.值更改时触发的回调。
Signature:签名:
function(event: object, value: any) => void
event
: The event source of the callbackevent
: 回调的事件源value
: nullvalue
:空
So what you need to do is use setFieldValue
and pass it to Autocomplete
like所以你需要做的是使用
setFieldValue
并将其传递给Autocomplete
就像
onChange={(e, value) => setFieldValue("city_id", value)}
You need to pass the name of your field and what value you want to get.您需要传递您的字段名称以及您想要获取的值。
Here is a working example这是一个工作示例
@vencovsky has provided the correct answer that is still working for me with Material UI 14.10.1. @vencovsky 提供了正确的答案,该答案仍然适用于 Material UI 14.10.1。
I'm adding a bit more to it as I have my field set to required
in using Yup
validation.我正在添加更多内容,因为我在使用
Yup
验证时将我的字段设置为required
。
To get this to work correctly I have the following: Yup
config:为了
Yup
正常工作,我有以下内容:是的配置:
validationSchema = {
Yup.object().shape({
contact: Yup.string().max(255).required('Contact is required'),
})
}
react:反应:
<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"
/>
)}
/>
When the user click on the Autocomplete
element, it fires the onOpen
which runs the Formik
onBlur
and marks the field as touched.当用户单击
Autocomplete
元素时,它会触发onOpen
运行Formik
onBlur
并将该字段标记为已触摸。 If an item is then not picked, Formik flags
the field and displays the Contact is required
validation message.如果随后未选取项目,Formik 会
flags
该字段并显示Contact is required
验证消息。
You have to add onChange = {(event, value) => handleChange(value)}
in Autocomplete
tag as您必须在
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);
If onChange don't work you can use onInputChange as well.如果 onChange 不起作用,您也可以使用 onInputChange。
I had the same issue recently and solved.我最近遇到了同样的问题并解决了。 Sharing my experience
分享我的经验
Updating formik values directly on OnChange
method solved the issue直接在
OnChange
方法上更新 formik 值解决了这个问题
onChange={(event, value) => (formik.values.country = value!)}
Here is the full code这是完整的代码
Formik settings 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自动完成
<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.