Reputation: 357
I'm using formik with material-ui to build custom autocomplete component.
I add validation using yup for autocomplete to be required (user need to select one option):
validationSchema: Yup.object().shape({
skill: Yup.object().shape({
value: Yup.string().required(),
label: Yup.string().required()
})
}),
when user select any option I want it to save the option as {label,value} and not just the value because then I need to send it as object to the server.
I get some errors:
when I press submit I get error
Objects are not valid as a React child (found: object with keys {value, label}). If you meant to render a collection of children, use an array instead.
I get those warnings:
MUI: The value provided to Autocomplete is invalid. None of the options match with `{"label":"","value":""}`. You can use the `isOptionEqualToValue` prop to customize the equality test.
Warning: Failed prop type: Invalid prop `helperText` supplied to `ForwardRef(TextField)`, expected a ReactNode.
I'm trying to build reusable autocomplete component to be able to get the selected value as {label,value} without any error and working as expected. I'm not sure if my validation is the right way. I want just the user to select an option.
in addition, I would like to ask, can I store object details into the value not as string? if no, what the best way to store value of object as option?
is my yup schema is the right way? should I store id of object as value and then filter it? how to pass value as string to autocomplete and show it selected in autocomplete? How can I do it without skill schema as object, just as string like:
validationSchema: Yup.object().shape({
skill: Yup.string().required()
}),
Upvotes: 5
Views: 2057
Reputation: 3549
This is because initial value as {label:'' , value :''} is not in skills list. so in isOptionEqualToValue it will return false
simply remove isOptionEqualToValue prop and in value check if there is option with that value and if not set null
const getValueFromOptions = (value: string) => {
return (
options.find((option: any) => option.value === value) ?? null
);
};
and in auto complete :
<Autocomplete
value={getValueFromOptions(field.value)}
...
or check if field.value has value otherwise null
<Autocomplete
value={Boolean(field.value?.value) ? field.value : null}
...
and another error was from show error message because meta.error is object that contains value and label error so you need to show one of them, I changed it to this :
renderInput={(params) => {
const errorMsg = meta.error as { value?:string }
return (
<TextField
{...params}
label={label}
name={name}
error={showError}
helperText={meta.touched && errorMsg?.value}
/>
);
}}
and another error was from show error message, it was displaying 'skill.value is a required field' so I simply add new message in yup validation
validationSchema: Yup.object().shape({
skill: Yup.object().shape({
value: Yup.string().required('skill is a required field'),
label: Yup.string()
})
}),
you see pure code here : https://codesandbox.io/s/blissful-nova-nqvxq2?file=/src/components/AutocompleteField.tsx
Upvotes: 3