I have a reusable Autocomplete component, and I need to get the selected object, but I'm not able to access this information outside the component.
See that on the component I can access the information.
But on the form I can't access this information.
How can I access the selected object on the form?
I thank you for your help!
Autocomplete:
import * as React from "react";
import { FieldProps, getIn } from "formik";
import { TextField, CircularProgress } from "@material-ui/core";
import MuiAutocomplete, {
createFilterOptions
} from "@material-ui/lab/Autocomplete";
const NewAutocomplete: React.FC<
FieldProps & {
label?: string,
options: Array<{ label: string, value: number }>
}
> = ({ textFieldProps, field, form, label, options, isLoading, ...props }) => {
const filterOptions = createFilterOptions({
matchFrom: "start",
limit: 500
});
const errorText =
getIn(form.touched, field.name) && getIn(form.errors, field.name);
const valueInit = [
{
value: 0,
label: ""
}
];
return (
<MuiAutocomplete
{...props}
{...field}
filterOptions={filterOptions}
options={[...valueInit, ...options]}
getOptionLabel={(option) => (option ? option.label : "")}
getOptionSelected={(option, value) => option.value === value?.value}
loading={isLoading}
value={field.value}
onChange={(e, value) => {
form.setFieldValue(field.name, value);
//console.log(value);
}}
renderInput={(props) => (
<>
<TextField
{...props}
{...textFieldProps}
label={label}
helperText={errorText?.value || errorText}
error={!!errorText}
InputProps={{
...props.InputProps,
endAdornment: (
<React.Fragment>
{isLoading ? (
<CircularProgress color="primary" size={20} />
) : null}
{props.InputProps.endAdornment}
</React.Fragment>
)
}}
/>
</>
)}
/>
);
};
export default NewAutocomplete;
Form:
import { Grid } from "@material-ui/core";
import { Field, Form, Formik } from "formik";
import Autocomplete from "./component/Autocomplete";
const listFilms = [
{ label: "The Shawshank Redemption", value: 1 },
{ label: "The Godfather", value: 2 },
{ label: "The Godfather: Part II", value: 3 },
{ label: "The Dark Knight", value: 4 }
];
const initialValues = {
film: {
label: "",
value: 0
}
};
export default function App() {
return (
<div className="App">
<Formik initialValues={initialValues}>
{function Render({ errors, touched, isSubmitting, setFieldValue }) {
return (
<Form id="form">
<Grid container direction="row">
<Grid item xs={12}>
<Field
name="film"
component={Autocomplete}
label="Film"
options={listFilms}
onChange={(e, value) => {
console.log(value);
}}
textFieldProps={{
fullWidth: true,
margin: "dense",
variant: "outlined",
autoFocus: true
}}
/>
</Grid>
</Grid>
</Form>
);
}}
</Formik>
</div>
);
}
I managed to solve passing the value via props: setFieldValue
Autocomplete:
import * as React from "react";
import { FieldProps, getIn } from "formik";
import { TextField, CircularProgress } from "@material-ui/core";
import MuiAutocomplete, {
createFilterOptions
} from "@material-ui/lab/Autocomplete";
const NewAutocomplete: React.FC<
FieldProps & {
label?: string,
options: Array<{ label: string, value: number }>
}
> = ({
textFieldProps,
field,
form,
label,
options,
isLoading,
setFieldValue,
...props
}) => {
const filterOptions = createFilterOptions({
matchFrom: "start",
limit: 500
});
const errorText =
getIn(form.touched, field.name) && getIn(form.errors, field.name);
const valueInit = [
{
value: 0,
label: ""
}
];
return (
<MuiAutocomplete
{...props}
{...field}
filterOptions={filterOptions}
options={[...valueInit, ...options]}
getOptionLabel={(option) => (option ? option.label : "")}
getOptionSelected={(option, value) => option.value === value?.value}
loading={isLoading}
value={field.value}
onChange={(e, value) => {
form.setFieldValue(field.name, value);
if (setFieldValue) {
setFieldValue(value);
}
}}
renderInput={(props) => (
<>
<TextField
{...props}
{...textFieldProps}
label={label}
helperText={errorText?.value || errorText}
error={!!errorText}
InputProps={{
...props.InputProps,
endAdornment: (
<React.Fragment>
{isLoading ? (
<CircularProgress color="primary" size={20} />
) : null}
{props.InputProps.endAdornment}
</React.Fragment>
)
}}
/>
</>
)}
/>
);
};
export default NewAutocomplete;
Form:
import { Grid } from "@material-ui/core";
import { Field, Form, Formik } from "formik";
import { useState } from "react";
import Autocomplete from "./component/Autocomplete";
const listFilms = [
{ label: "The Shawshank Redemption", value: 1 },
{ label: "The Godfather", value: 2 },
{ label: "The Godfather: Part II", value: 3 },
{ label: "The Dark Knight", value: 4 }
];
const initialValues = {
film: {
label: "",
value: 0
}
};
export default function App() {
const [autocompleteValue, setAutocompleteValue] = useState(null);
console.log(autocompleteValue);
return (
<div className="App">
<Formik initialValues={initialValues}>
{function Render({ formik, values, setFieldValue }) {
return (
<Form id="form">
<Grid container direction="row">
<Grid item xs={12}>
<Field
name="film"
component={Autocomplete}
label="Film"
options={listFilms}
textFieldProps={{
fullWidth: true,
margin: "dense",
variant: "outlined",
autoFocus: true
}}
setFieldValue={setAutocompleteValue}
/>
</Grid>
</Grid>
</Form>
);
}}
</Formik>
</div>
);
}
Console log:
{label: "The Godfather", value: 2}