Material Autocomplete select dropdown getting error while onchange - reactjs

Here is my code.
My problem : Cannot change the dropdown value. Getting error like Uncaught TypeError: Cannot read properties of undefined (reading 'id')
{formValues.map((element, index) => (
<div className="row mt-2" key={index}>
<div className='col-lg-4 mt-2' key={index}>
<Autocomplete
multiple
name="assignee"
limitTags={2}
id="assignee"
options={ownerList}
defaultValue={[{'text': formValues[index].AssigneeName, 'id': formValues[index].AssigneeId }]}
getOptionLabel={(option) => option.text}
onChange={(event, newValue) => {
console.log(newValue[0].id); // this line am getting error like Uncaught TypeError: Cannot read properties of undefined (reading 'id')
}}
disableClearable={true}
filterSelectedOptions
renderInput={(params) => (
<TextField
classes={{ root: classes.customTextField }}
{...params}
label="Select Assignee"
placeholder="Select Assignee"
className="auto-label"
/>
)}
/>
</div>
</div>
))}

Can you perhaps log console.log(newValue)? That would give you an insight on why you receive this error. Probably newValue[0] is undefined.
You can add optional chaining to prevent the Error. console.log(newValue[0]?.id);

Related

MUI: You have provided an out-of-range value `18:00` for the select component

I use react with Mui;
<Select
disabled={disable}
renderValue={(value) => renderValue(value as number)}
size="small"
value={object.time}
onChange={({ target }) => onChange(target.value as string)}
>
{hours.map((hour) => (
<MenuItem key={hour.id} value={hour.val1}>
<ListItemText title={hour.time} primary={hour.time} />
</MenuItem>
))}
</Select>
I tried using many solutions like add defaultValue="" or stringify the value but none helped

material ui - Autocomplete multiple error

I am using material-ui in React.js. When using multiple in Autocomplete it gives me the error,
Uncaught TypeError: (intermediate value)(intermediate value)(intermediate value).filter is not a function at useAutocomplete,
The above error occurred in the <ForwardRef(Autocomplete)> component:
in ForwardRef(Autocomplete).
material-ui version - "#mui/material": "^5.6.0",
Code:
<Autocomplete
multiple={true}
disableCloseOnSelect
id={field.name}
name={field.name}
options={locations}
value={props.values.locationId}
size="small"
autoComplete={false}
onChange={(e, newValue) => {
props.setFieldValue(
'locationId',
newValue ? newValue : '',
true,
);
}}
onBlur={() =>
props.setFieldTouched(field.name, true)
}
getOptionLabel={(option) =>
option['name'] ? option['name'] : ''
}
renderOption={(props, option, { selected }) => (
<li {...props}>
<Checkbox
style={{ marginRight: 8 }}
checked={selected}
/>
{option.title}
</li>
)}
renderInput={(params) => (
<TextField
{...params}
fullWidth
size="small"
placeholder={field.placeholder}
variant="outlined"
/>
)}
/>
When using multiple, value must be an array (see multiple in the docs). I found this answer helpful for using a controlled Autocomplete component in multiple mode, as you're doing here.

Create tag using Autocomplete material UI when user input anything

I can type something which shows selected tags from the dropdown list but I want a user can type something and create a tag or multiple tags separated by a comma.
I used a useState hook which is an array.
const [tags, setTags] = useState([]);
I set the Autocomplete like the following code -
<Autocomplete
style={{ margin: "10px 0" }}
multiple
id="tags-outlined"
options={tags}
defaultValue={[]}
freeSolo
renderTags={(value, getTagProps) =>
value.map((option, index) => (
<Chip variant="outlined" label={option} {...getTagProps({ index })} />
))
}
renderInput={(params) => (
<TextField
{...params}
label="Tags"
placeholder="Tags"
value={tags}
onChange={(e) => setTags([...tags, e.target.value.split(",")])}
/>
)}
/>;
Surprisingly, I tried for an hour before questioning. But Solve it within a few moments after putting the question.
Here's the solution-
<Autocomplete
style={{ margin: "10px 0" }}
multiple
id="tags-outlined"
options={tags}
defaultValue={[...tags]}
freeSolo
autoSelect
onChange={(e) => setTags([...tags, e.target.value])}
renderInput={(params) => (
<TextField
{...params}
label="Tags"
placeholder="Tags"
value={tags}
/>
)}
/>;
the output will look like this.
user input tag
but I want to add multiple tags that didn't happen right now which can be put via giving a space or comma.
Partly relevant but I think it can be helpful for someone using React Hook Form library with MUI5.
Storing tags in the state would render them being saved in form data when submitted. Instead, you need to use their onChange function.
const Tags = ()=>{
const { control,handleSubmit } = useForm({
defaultValues: {
checkbox: true,
autocomplete:["test"]
}
});
const onSubmit = data => console.log(data);
return <>
<form onSubmit={handleSubmit(onSubmit)}>
<Controller
name="autocomplete"
control={control}
render={({ field }) => {
const {value,onChange} = field
return <Autocomplete
style={{ margin: "10px 0" }}
multiple
id="tags-outlined"
options={value}
defaultValue={[...value]}
freeSolo
autoSelect
onChange={((e)=>onChange([...value,e.target.value]))}
renderInput={(params) => {
return <TextField
{...params}
label="Tags"
placeholder="Tags"
value={value}
/>
}}
></Autocomplete>
}
}
/>
<input type="submit" />
</form>
</>
}

How to add error message to yup validation for array containing distinct values in FieldArray?

I am trying to add Error message for my Field Array which should contain array of distinct elements. Below is my validation:
export const emails = yup
.array(
yup
.string()
.matches(/^\S+#\S+$/, {
message: "Must be a valid email id"
})
)
.test("Unique", "Email ids need to be unique", values => {
return new Set(values).size === values.length;
});
And here is the ErrorMessage component inside my FieldArray component's render prop:
render={({ form, push, remove }) => (
<div>
{range(0, form.values[name].length).map(i => (
<div className={styles.inputContainer} key={i}>
<div>
<InputComponent name={`${name}.${i}`} {...props} />
<Button color="danger" onClick={() => remove(i)}>
<FaTimes />
</Button>
</div>
<ErrorMessage
name={`${name}.${i}`}
render={msg => (
<FormFeedback style={{ display: "block" }}>
{msg}
</FormFeedback>
)}
/>
</div>
))}
<Button
color="info"
onClick={() => push("")}
disabled={disabled || form.values[name].slice(-1)[0] === ""}
>
<FaPlus />
</Button>
</div>
)}
However I get the error message as shown below. The message comes as one by one letter. I understand because I am including it in my range render method. But I have included the Error message component inside, because I want to show the error for invalid email ids as well.
I, with help of someone figured out the solution. Let me jot it down if anybody needs it.
Basically, the Error message component prints out any error messages generated. It is not able to distinguish between where and what from the error messages.
So, I made use of of form attribute from render props of FieldArray component. The error message comes as a property of form as form.errors.
However the key to distinguish between the two ErrorMessage components is that the inner form.errors comes as an array and the outer one comes as a string. So the solution is to check the datatype of form.errors object. Below is the code snippet.
render={({ form, push, remove }) => (
<div>
{range(0, form.values[name].length).map(i => {
return (
<div className={styles.inputContainer} key={i}>
<div>
<InputComponent name={`${name}.${i}`} {...props} />
<Button color="danger" onClick={() => remove(i)}>
<FaTimes />
</Button>
</div>
{typeof form.errors[name] !== "string" && (
<ErrorMessage
name={`${name}.${i}`}
render={msg => {
return (
<FormFeedback style={{ display: "block" }}>
{msg}
</FormFeedback>
);
}}
/>
)}
</div>
);
})}
{typeof form.errors[name] === "string" && (
<ErrorMessage
name={`${name}`}
render={msg => (
<FormFeedback style={{ display: "block" }}>
{msg}
</FormFeedback>
)}
/>
)}

Material UI Autocomplete

I am building a form using Material UI's autocomplete feature. The field renders chips however I am unable to modify the onDelete prop of the chip component. I have tried modifying other props such as the variant, label, etc but even trying to get the onDelete prop to do a simple console log does not work. My code is below.
<Autocomplete
onChange={handleRecChange("foodRecs")}
multiple
options={menuItems}
renderTags={(value, getTagProps) =>
value.map((option, index) => (
<Chip
variant="outlined"
key={option}
label={option}
onDelete={() => console.log("test")}
{...getTagProps({ index })}
/>
))
}
renderInput={params => (
<TextField
{...params}
variant="standard"
label="Recommendations"
placeholder="Choose anything from the menu"
fullWidth
/>
)}
/>
That's because you override onDelete in this line:
{...getTagProps({ index })}
getTagProps is a getter for the tag props. It includes onDelete function, since onDelete is a Chip property (you can print the getTagProps return value to see that).
You should placegetTagProps on the first line, to avoid unwanted prop overrides:
<Chip
{...getTagProps({ index })}
variant="outlined"
key={option}
label={option}
onDelete={() => console.log("test")}
/>

Resources