我正在尝试找出如何遵循Formik,Material UI,React工具here的“自动完成”字段的文档中的说明。
文档中给出的示例为:
import { Autocomplete } from 'formik-material-ui-lab';
const options = [{ title: 'The Shawshank Redemption', year: 1994 }, ...]
<Field
name="name"
component={Autocomplete}
options={options}
getOptionLabel={(option: Movie) => option.title}
style={{ width: 300 }}
renderInput={(params: AutocompleteRenderInputParams) => (
<TextField
{...params}
error={touched['name'] && !!errors['name']}
helperText={errors['name']}
label="Autocomplete"
variant="outlined"
/>
)}
/>;
在getOptionLabel中使用Movie的含义没有任何线索。当我尝试使用此方法时,Movie带有下划线,并且renderInput对象中的AutocompleteRenderInputParams也带有下划线。我不知道为什么。
我看到了这个post尝试了另一种方法,但是我也无法使它起作用。
我有一个带有两个“自动完成”字段的表单。目前看起来像这样。
当我尝试使用该表单时,提交按钮挂起,控制台日志显示:
Material-UI:返回了自动完成的
getOptionLabel
方法 未定义,而不是“”的字符串。
import React, { useState } from 'react';
import { Link } from 'react-router-dom';
import firebase, {firestore} from '../../../firebase';
import { withStyles } from '@material-ui/core/styles';
import TextField from '@material-ui/core/TextField';
import Button from '@material-ui/core/Button';
import Box from '@material-ui/core/Box';
import Typography from '@material-ui/core/Typography';
import Grid from '@material-ui/core/Grid';
import Dialog from '@material-ui/core/Dialog';
import DialogActions from '@material-ui/core/DialogActions';
import DialogContent from '@material-ui/core/DialogContent';
import DialogContentText from '@material-ui/core/DialogContentText';
import DialogTitle from '@material-ui/core/DialogTitle';
import {
Formik, Form, Field, ErrorMessage,
} from 'formik';
import * as Yup from 'yup';
import { Autocomplete, ToggleButtonGroup } from 'formik-material-ui-lab';
import { Switch } from 'formik-material-ui';
const styles = {
};
const allCategories = [
{value: 'culture', label: 'Culture'},
{value: 'other', label: 'Other'},
];
const sharingOptions = [
{value: 'open', label: 'Openly'},
{value: 'me', label: 'Only me'},
];
function Contact(props) {
const { classes } = props;
const [open, setOpen] = useState(false);
const [isSubmitionCompleted, setSubmitionCompleted] = useState(false);
function handleClose() {
setOpen(false);
}
function handleClickOpen() {
setSubmitionCompleted(false);
setOpen(true);
}
return (
<React.Fragment>
<Button
// component="button"
color="primary"
onClick={handleClickOpen}
style={{ float: "right"}}
variant="outlined"
>
Create an Impact Metric
</Button>
<Dialog
open={open}
onClose={handleClose}
aria-labelledby="form-dialog-title"
>
{!isSubmitionCompleted &&
<React.Fragment>
<DialogTitle id="form-dialog-title">Create an Impact Metric</DialogTitle>
<DialogContent>
<DialogContentText>
test form.
</DialogContentText>
<Formik
initialValues={{ title: "", category: "", sharing: "" }}
onSubmit={(values, { setSubmitting }) => {
setSubmitting(true);
firestore.collection("testing").doc().set({
values,
createdAt: firebase.firestore.FieldValue.serverTimestamp()
})
.then(() => {
setSubmitionCompleted(true);
});
}}
validationSchema={Yup.object().shape({
title: Yup.string()
.required('Required'),
category: Yup.string()
.required('Required'),
sharing: Yup.string()
.required('Required')
})}
>
{(props) => {
const {
values,
touched,
errors,
dirty,
isSubmitting,
handleChange,
handleBlur,
handleSubmit,
handleReset,
} = props;
return (
<form onSubmit={handleSubmit}>
<TextField
label="Title"
name="title"
className={classes.textField}
value={values.title}
onChange={handleChange}
onBlur={handleBlur}
helperText={(errors.title && touched.title) && errors.title}
margin="normal"
style={{ width: "100%"}}
/>
<Box margin={1}>
<Field
name="category"
component={Autocomplete}
options={allCategories}
getOptionLabel={option => option.label}
style={{ width: 300 }}
renderInput={(params: AutocompleteRenderInputParams) => (
<TextField
{...params}
error={touched['category'] && !!errors['category']}
helperText={
touched['category'] && errors['category']
}
label="Select Category"
variant="outlined"
/>
)}
/>
</Box>
<Box margin={1}>
<Field
name="sharing"
component={Autocomplete}
options={sharingOptions}
getOptionLabel={option => option.label}
style={{ width: 300 }}
renderInput={(params: AutocompleteRenderInputParams) => (
<TextField
{...params}
error={touched['sharing'] && !!errors['sharing']}
helperText={
touched['sharing'] && errors['sharing']
}
label="Select Sharing Option"
variant="outlined"
/>
)}
/>
</Box>
<DialogActions>
<Button
type="button"
className="outline"
onClick={handleReset}
disabled={!dirty || isSubmitting}
>
Reset
</Button>
<Button type="submit" disabled={isSubmitting}>
Submit
</Button>
{/* <DisplayFormikState {...props} /> */}
</DialogActions>
</form>
);
}}
</Formik>
</DialogContent>
</React.Fragment>
}
{isSubmitionCompleted &&
<React.Fragment>
<DialogTitle id="form-dialog-title">Thanks!</DialogTitle>
<DialogContent>
<DialogContentText>
test
</DialogContentText>
<DialogActions>
<Button
type="button"
className="outline"
onClick={handleClose}
>
Close
</Button>
{/* <DisplayFormikState {...props} /> */}
</DialogActions>
</DialogContent>
</React.Fragment>}
</Dialog>
</React.Fragment>
);
}
export default withStyles(styles)(Contact);
任何人都可以看到如何与上面链接中发布的文档一致地使用Formik,材料ui进行自动完成吗?
我也尝试使用常规选择表单输入。这是表单字段:
<Box margin={1}>
<Field
component={TextField}
type="text"
name="category"
label="Category"
select
variant="outlined"
helperText="Select a category"
margin="normal"
style={{ width: "100%"}}
InputLabelProps={{
shrink: true,
}}
>
{allCategories.map(option => (
<MenuItem key={option.value} value={option.value}>
{option.label}
</MenuItem>
))}
</Field>
尝试此操作时,我在控制台中收到一条警告:
instrument.ts:129 Material-UI: You have provided an out-of-range value `undefined` for the select component.
Consider providing a value that matches one of the available options or ''
此警告没有任何意义-表单呈现时菜单正确填充。
我还收到一条错误消息:
index.js:1警告:组件正在更改的不受控制的输入 类型undefined要控制。输入元素不应从 不受控制到受控制(反之亦然)。确定使用 受控或非受控输入元件的使用寿命 零件。更多信息
关于该错误,我看到了这个post,它建议使用值(而不是输入-我这样做)并将所有初始值定义为一种类型。对我来说,它们都是字符串,尽管我尝试用空数组替换选择字段。在这两种选择中,控制台都会返回相同的错误消息。
在这一点上-我不在乎自动填充或选择使用哪个,我只想让其中一个工作。
有趣的是,在两种情况下(使用选择和自动完成功能),控制台都会记录警告:
Material-UI: You have provided an out-of-range value `undefined` for the select component.
Consider providing a value that matches one of the available options or ''.
The available values are `one`, `two`.
(anonymous) @ 0.chunk.js:141301
0.chunk.js:141301 Material-UI: You have provided an out-of-range value `undefined` for the select component.
Consider providing a value that matches one of the available options or ''.
The available values are `a`, `b`, `c`, `d`.
但是,只有一个错误实例显示:
A component is changing an uncontrolled input of type undefined to be controlled. Input elements should not switch from uncontrolled to controlled (or vice versa). Decide between using a controlled or uncontrolled input element for the lifetime of the component. More info: react-website -controlled-components
in input (created by ForwardRef(SelectInput))
in ForwardRef(SelectInput) (created by ForwardRef(InputBase))
in div (created by ForwardRef(InputBase))
in ForwardRef(InputBase) (created by WithStyles(ForwardRef(InputBase)))
in Wi
此错误指向类别选择表单输入。
我还尝试将code sandbox中的性别选择表单字段添加到表单中,以查看是否可以使用此功能。当我注释掉上述类别和共享字段,并添加默认值为空字符串的性别字段时,将加载表单。
字段为:
<Field
name="gender"
label="Gender"
options={[
{ value: "Male", label: "Male" },
{ value: "Female", label: "Female" },
{ value: "Other", label: "Other" }
]}
component={Select}
/>
出现性别选择字段,但宽度约为1厘米,并且选项菜单中没有选项,我什么也无法选择。但是表单确实会加载到firebase中,性别字段中使用空字符串。那是进步,但还不足以推进。
同一代码沙箱显示了一个使用“自动完成”的字段。我尝试对其进行调整,并以如下形式在其形式中使用它:
<Field
name="gender"
label="Gender"
options={sharingOptions}
component={Autocomplete}
textFieldProps={{
label: sharingOptions.label
}}
/>
尝试此操作时,出现错误消息:
TypeError:renderInput不是函数
此错误消息对我来说毫无意义,因为我没有在表单的任何地方使用renderInput。
当我尝试时:
<Box margin={1}>
<Field
component={Select}
type="text"
name="category"
label="Impact Category"
select
variant="outlined"
helperText="Select a category"
margin="normal"
style={{ width: "100%"}}
InputLabelProps={{
shrink: true,
}}
>
{allCategories.map(option => (
<MenuItem key={option.value} value={option.value}>
{option.label}
</MenuItem>
))}
</Field>
</Box>
我没有任何错误,可以保存带有选项详细信息的表单。但是,这实际上并不能解决有关“自动完成”为何不起作用的问题。这也没有使用链接文档中所示的“选择”字段。因此,我不清楚这为什么起作用,或者为什么文档中显示的方法不起作用。
下一个尝试
使用此codesandbox中的自动填充示例作为指南,我尝试过:
<Field
name="autocomplete"
multiple
component={Autocomplete}
options={sharingOptions}
getOptionLabel={(option: any) => option.title}
style={{width: 300}}
renderInput={(params: AutocompleteRenderInputParams) => (
<MuiTextField
{...params}
error={touched['autocomplete'] && !!errors['autocomplete']}
helperText={touched['autocomplete'] && errors['autocomplete']}
label="Autocomplete"
variant="outlined"
/>
)}
/>
与前面的示例一样,我的代码编辑器在getOptionLabel中出现的值“ any”下划线,并在AutocompleteRenderInputParams下划线。我找不到任何文档来解释表单字段的这些元素的含义或作用。无论如何,我已经导入了AutocompleteRenderInputParams,如代码沙箱所示。
我在表单中将自动完成字段的初始值设置为一个空数组-尽管我注意到在此示例中代码沙箱未设置初始值。当我尝试删除自动完成的初始值时,我得到的错误与初始值是一个空数组时产生的错误相同,但是在控制台中我也收到一条警告,提示:
警告:自动完成的值不是数组,这可能导致 意外的行为
当我尝试此代码时,控制台会记录以下错误:
TypeError:无法读取未定义的属性“ toLowerCase”
Material-UI:返回了自动完成的
getOptionLabel
方法 未定义,而不是{“ value”:“ open”,“ label”:“ Open “}。
答案 0 :(得分:3)
工作示例:
import React from "react";
import ReactDOM from "react-dom";
import "./styles.css";
import { Formik, Field } from "formik";
import { Autocomplete } from "formik-material-ui-lab";
import { TextField } from "@material-ui/core";
const options = [
{ title: "The Shawshank Redemption", year: 1994 },
{ title: "Inglourious Basterds", year: 2009 },
{ title: "Snatch", year: 2000 },
{ title: "3 Idiots", year: 2009 },
{ title: "Monty Python and the Holy Grail", year: 1975 }
];
function App() {
return (
<Formik
initialValues={{
autocomplete: null
}}
>
{() => (
<Field
name="autocomplete"
component={Autocomplete}
options={options}
getOptionLabel={(option) => option.title}
style={{ width: 300 }}
renderInput={(params) => (
<TextField {...params} label="Autocomplete" variant="outlined" />
)}
/>
)}
</Formik>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
答案 1 :(得分:1)
对于其他被卡住的人,这是可行的-尽管我不明白为什么。上面文章中指出的带下划线的错误仍然存在,我不知道如何解决。
将此作为一种前进方式-而不是一个好的解决方案。
import React, { useState } from 'react';
import {render} from 'react-dom';
import { Link } from 'react-router-dom';
import firebase, {firestore} from '../../../../firebase';
import { withStyles } from '@material-ui/core/styles';
import {
Button,
LinearProgress,
MenuItem,
FormControl,
InputLabel,
FormControlLabel,
TextField,
Typography,
Box,
Grid,
Checkbox,
Dialog,
DialogActions,
DialogContent,
DialogContentText,
DialogTitle,
} from '@material-ui/core';
import MuiTextField from '@material-ui/core/TextField';
import ToggleButton from '@material-ui/lab/ToggleButton';
import FormatAlignLeftIcon from '@material-ui/icons/FormatAlignLeft';
import FormatAlignCenterIcon from '@material-ui/icons/FormatAlignCenter';
import FormatAlignRightIcon from '@material-ui/icons/FormatAlignRight';
import FormatAlignJustifyIcon from '@material-ui/icons/FormatAlignJustify';
import {
Formik, Form, Field, ErrorMessage,
} from 'formik';
import * as Yup from 'yup';
// import { Autocomplete, ToggleButtonGroup } from 'formik-material-ui-lab';
import {
Autocomplete,
ToggleButtonGroup,
AutocompleteRenderInputParams,
} from 'formik-material-ui-lab';
import {
fieldToTextField,
TextFieldProps,
Select,
Switch,
} from 'formik-material-ui';
const allCategories = [
{value: 'one', label: 'Col'},
{value: 'two', label: 'Com'},
];
function UpperCasingTextField(props: TextFieldProps) {
const {
form: {setFieldValue},
field: {name},
} = props;
const onChange = React.useCallback(
event => {
const {value} = event.target;
setFieldValue(name, value ? value.toUpperCase() : '');
},
[setFieldValue, name]
);
return <MuiTextField {...fieldToTextField(props)} onChange={onChange} />;
}
function Glossary(props) {
const { classes } = props;
const [open, setOpen] = useState(false);
const [isSubmitionCompleted, setSubmitionCompleted] = useState(false);
function handleClose() {
setOpen(false);
}
function handleClickOpen() {
setSubmitionCompleted(false);
setOpen(true);
}
return (
<React.Fragment>
<Button
// component="button"
color="primary"
onClick={handleClickOpen}
style={{ float: "right"}}
variant="outlined"
>
Create a Defined Term
</Button>
<Dialog
open={open}
onClose={handleClose}
aria-labelledby="form-dialog-title"
>
{!isSubmitionCompleted &&
<React.Fragment>
<DialogTitle id="form-dialog-title">Create </DialogTitle>
<DialogContent>
<DialogContentText>
</DialogContentText>
<Formik
initialValues={{ term: "", definition: "", category: [], attribution: true, attributionRegion: '', context: "", relatedTerms: "", linkedTemplates: "", referenceMaterials: "" }}
onSubmit={(values, { setSubmitting }) => {
setSubmitting(true);
firestore.collection("glossary").doc().set({
...values,
createdAt: firebase.firestore.FieldValue.serverTimestamp()
})
.then(() => {
setSubmitionCompleted(true);
});
}}
validationSchema={Yup.object().shape({
term: Yup.string()
.required('Required'),
definition: Yup.string()
.required('Required'),
category: Yup.string()
.required('Required'),
attribution: Yup.boolean()
.required('Required'),
context: Yup.string()
.required("Required"),
})}
>
{(props) => {
const {
values,
touched,
errors,
dirty,
isSubmitting,
handleChange,
handleBlur,
handleSubmit,
handleReset,
} = props;
return (
<form onSubmit={handleSubmit}>
<TextField
label="Term"
name="term"
className={classes.textField}
value={values.term}
onChange={handleChange}
onBlur={handleBlur}
helperText={(errors.term && touched.term) && errors.term}
margin="normal"
style={{ width: "100%"}}
/>
<TextField
label="Meaning"
name="definition"
multiline
rows={4}
className={classes.textField}
value={values.definition}
onChange={handleChange}
onBlur={handleBlur}
helperText={(errors.definition && touched.definition) && errors.definition}
margin="normal"
style={{ width: "100%"}}
/>
<TextField
label="How is it used?"
name="context"
className={classes.textField}
multiline
rows={4}
value={values.context}
onChange={handleChange}
onBlur={handleBlur}
helperText={(errors.context && touched.context) && errors.context}
margin="normal"
style={{ width: "100%"}}
/>
<Box margin={1}>
<Typography component="div" style={{ marginTop: "5vh", marginBottom: "5vh"}}>
Choose)?
<Grid component="label" container alignItems="center" spacing={1}>
<Grid item>Attribution</Grid>
<Grid item>
<Field
component={Switch}
name="attribution"
type="checkbox"
>
</Field>
</Grid>
<Grid item>Anonymous</Grid>
</Grid>
</Typography>
</Box>
<Box margin={1}>
<Field
name="category"
multiple
component={Autocomplete}
options={allCategories}
getOptionLabel={(option: any) => option.label}
style={{width: 300}}
renderInput={(params: AutocompleteRenderInputParams) => (
<MuiTextField
{...params}
error={touched['autocomplete'] && !!errors['autocomplete']}
helperText={touched['autocomplete'] && errors['autocomplete']}
label="Category"
variant="outlined"
/>
)}
/>
</Box>
<DialogActions>
<Button
type="button"
className="outline"
onClick={handleReset}
disabled={!dirty || isSubmitting}
>
Reset
</Button>
<Button type="submit" disabled={isSubmitting}>
Submit
</Button>
{/* <DisplayFormikState {...props} /> */}
</DialogActions>
</form>
);
}}
</Formik>
</DialogContent>
</React.Fragment>
}
{isSubmitionCompleted &&
<React.Fragment>
<DialogTitle id="form-dialog-title">Thanks!</DialogTitle>
<DialogContent>
<DialogContentText>
Thank you </DialogContentText>
<DialogActions>
<Button
type="button"
className="outline"
onClick={handleClose}
>
Close
</Button>
{/* <DisplayFormikState {...props} /> */}
</DialogActions>
</DialogContent>
</React.Fragment>}
</Dialog>
</React.Fragment>
);
}
export default withStyles(styles)(Glossary);