Material UI Autocomplete - Search only from the beginning of the word - reactjs

I'm using material UI Autocomplete field in my React application and I want the search in it to work only from the beginning of the keyword (for some fields of the objects):
For example, if the options are
[
{data1:'abc', data2:'a123'},
{data1:'cba', data2:'345'},
{data1:'bca3', data2:'654'}
]
and I type a - only the first option should appear.
If I type 3 - only the second option should appear.

I'd like to add some extra infos about filtering. You can also use the createFilterOptions provided from the MUI Autocomplete.
Example:
import { createFilterOptions } from '#material-ui/lab/Autocomplete';
const filterOptions = createFilterOptions({
matchFrom: 'start',
stringify: option => option.title,
});
<Autocomplete filterOptions={filterOptions} />
You can set some optional filters:
ignoreAccents (Boolean [optional])
ignoreCase (Boolean [optional])
limit (Number [optional])
matchFrom ('any' | 'start' [optional])
stringify (Func [optional])
trim (Boolean [optional])
https://material-ui.com/components/autocomplete/
Hope this could help someone!

Made it work with filterOptions Autocomplete prop and 'match-sorter' library:
const filterOptions = (options,{ inputValue }) =>
matchSorter(options, inputValue, {
keys: [
{ threshold: matchSorter.rankings.STARTS_WITH, key: 'data1' },
{ threshold: matchSorter.rankings.STARTS_WITH, key: 'data2' },
'data3',
],
});

https://material-ui.com/components/autocomplete/#multiple-values
It works,
You need to add
multiple
<Autocomplete
multiple
id="tags-standard"
options={top100Films}
getOptionLabel={option => option.title}
defaultValue={[top100Films[13]]}
renderInput={params => (
<TextField
{...params}
variant="standard"
label="Multiple values"
placeholder="Favorites"
/>
)}
/>

Related

Material UI's Autocomplete does not show the selected value in React using react-hook-form

I am having issues making Material UI's Autocomplete show the selected item using react-hook-form with options that are objects containing name and id. When I select an item, the box is just empty.
I have a FieldArray of custom MaterialBars which contain a material:
<Controller
control={control}
name={`materialBars.${index}.materialId`}
render={(
{ field: { value, onChange } }
) => (
<Autocomplete
options={materials.map(material => ({id: material.id, name: material.name})} // materials are fetched from the API
getOptionLabel={(option) => option.name}
value={materialItems.find((item) => `${item.id}` === value) || null}
onChange={(_, val) => onChange(val?.id)}
renderInput={(params) => <TextField {...params} label="Material" />}
/>
)}
/>
There is a working example in the codesandbox.
When I select a material in the list, the box is cleared, and the placeholder text is shown instead of the selected material (when focus is removed from the box). The item is selected under the hood, because in my application, when I press submit, the newly selected material is saved to the backend.
I cannot figure out if the issue lies in the react-hook-form part, material UI or me trying to connect the two. I guess it will be easier if the options are just an array of strings with the name of the material (when the form schema has just the materialId), but it is nice to keep track of the id, for when contacting the API.
You should set the same type on materialId property between FormValue and ListData.
For Example, if I use number type, it should be
https://codesandbox.io/s/autocomplete-forked-mpivv1?file=/src/MaterialBar.tsx
// App.tsx
const { control, reset } = useForm<FormValues>({
defaultValues: {
materialBars: [
// use number instead of string
{ ..., materialId: 1 },
{ ..., materialId: 6 }
]
}
});
// util.ts
export const materials = [
{
id: 1, // keep it as number type
...
},
...
];
// util.ts
export type FormValues = {
materialBars: {
// change it from string type to number
materialId: number;
...
}[];
};
// MaterialBar.tsx
<Controller
...
) => (
<Autocomplete
...
/*
Remove curly brackets
- change`${item.id}` to item.id
*/
value={materialItems.find((item) => item.id === value) || null}
/>
)}
/>

How to make MUI's Autocomplete display the label from the matching value in props.options?

I have a multilingual website where there are certain Autocompletes whose options array need to have its items labels translated, which is done very easily.
However, it would be harder to update the current chosen value, stored elsewhere. Since Autocomplete uses the label from the value prop instead of using the item of same ID within options, it ends up like this:
const vehicles = [
{ id: 1, label: "Car" },
{ id: 2, label: "Bus" }
];
const currentVehicleValue = {
id: 2,
label: "Ônibus"
};
export default function ComboBox() {
return (
<Autocomplete
disablePortal
id="combo-box-demo"
options={vehicles}
value={currentVehicleValue}
renderInput={(params) => <TextField {...params} label="Vehicle" />}
/>
);
}
Is there a way to just tell Autocomplete to use the label inside the options prop instead of the one within the value
demo
EDIT: I mean to have the label within options being shown while I don't type anything. As in, the language changed, the options were translated, but the currentValue was not, so it would be nice to have the Autocomplete use the label from the matching item within options as long as I don't type anything.
Edit after clarification
You can change how the <TextField/> is rendered by tweaking the props it receives.
In the example below, I find the currentVehicle by its id and change the inputProps.value to be the vehicle label.
Also, to ensure MUI finds the currentValue correctly within the options, you will need to use the isOptionEqualToValue to compare the options ids instead of strict equality
const vehicles = [
{ id: 1, label: "Car" },
{ id: 2, label: "Bus" }
];
const currentVehicleValue = {
id: 2,
label: "Ônibus"
};
function compareValueToOption(option, value) {
return option.id === value.id;
}
function ComboBox() {
return (
<Autocomplete
disablePortal
id="combo-box-demo"
options={vehicles}
value={currentVehicleValue}
renderInput={ComboBoxInput}
isOptionEqualToValue={compareValueToOption}
/>
);
}
function ComboBoxInput(props) {
const currentVehicle = vehicles.find(
(vehicle) => vehicle.id === currentVehicleValue.id
);
props.inputProps.value = currentVehicle.label;
return <TextField {...props} label="Vehicle" />;
}
Here's a working demo

Material UI Autocomplete not updating input value (React)

I made an Autocomplete component in React using Material UI's Autocomplete component. Here's the code
import { useState } from "react";
import { Autocomplete as MuiAutcomplete } from "#mui/material";
import {useFormContext} from "react-hook-form";
interface props {
name: string,
options?: string[],
getOptions?: (value: string) => {
label: string,
id: number
}[] | string[],
freeSolo?: boolean
};
const Autocomplete = ({name, options=[], getOptions, freeSolo=false}: props) => {
const [autocompleteValues, setAutocompleteValues] = useState<any[]>(options);
const {setValue, getValues} = useFormContext();
return (
<MuiAutcomplete
options={autocompleteValues}
renderInput={({ InputProps, inputProps }) => (
<div ref={InputProps.ref}>
<input
type="text"
{...inputProps}
className="bg-transparent outline-none p-1"
/>
</div>
)}
value={getValues(name)}
onChange={(e, v) => {
setValue(name, v);
}}
getOptionLabel={(option) => option.label || option}
freeSolo={freeSolo}
/>
)
}
export default Autocomplete;
The options display just fine when I type but when actually selecting an option the input field doesn't actually get updated. It instead shows this error:
`MUI: The value provided to Autocomplete is invalid.None of the options match with `""`.You can use the `isOptionEqualToValue` prop to customize the equality test. `
I'm not entirely sure what's going on. Here's a video showing the error in case you need clarification https://imgur.com/a/xfm1mpb (sorry for low res, Imgur's compression ruined it)
Can you please details about what options are you passing?
It will be better if you can provide a codesandbox.
It is due to the option which you are selecting is not matching the value in options
The "" value is an actual value for auto complete. If you want to make it work with an empty field you can:
// Set value to null. If you set it to 'undefined' it will give you a warning similar to the current one
value={getValues(name) || null}
Or
// Override the function which checks if the value is equal to the option.
// Basically, you handle the empty string here.
isOptionEqualToValue={(option, currentValue) => {
if (currentValue === '') return true;
return option.name === currentValue.name;
}}

Autocomplete Material UI search based on two attributes

I have this data:
const sample = [
{hero: 'DARTH VADER', faction: 'EMPIRE'},
{hero: 'LUKE SKYWALKER', faction: 'REBEL'},
{hero: 'GREEDO', faction: 'BOUNTY HUNTER'},
];
Using Autocomplete, I am able to search the value via either hero or faction attribute by assigning one of them in getOptionLabel={(option) => {option.hero}} or getOptionLabel={(option) => {option.faction}} prop.
However I would like to be able to search using both of these attributes at the same time (typing either DARTH VADER or EMPIRE will return the same result).
The questions are as follows:
Can I achieve that using a single autocomplete?
If not, can we use a toggle to change which attribute to look for in the autocomplete?
Many thanks
Autocomplete provides the filterOptions prop.
you can use it to provide a custom filter like so (here's a codesandbox):
import React from 'react';
import TextField from '#material-ui/core/TextField';
import Autocomplete, { createFilterOptions } from '#material-ui/lab/Autocomplete';
const filterOptions = createFilterOptions({
matchFrom: 'any',
stringify: (option) => option.hero + option.faction,
});
export default function Filter() {
return (
<Autocomplete
id="filter-demo"
options={sample}
getOptionLabel={(option) => option.hero}
filterOptions={filterOptions}
renderInput={(params) => <TextField {...params} label="Custom filter" variant="outlined" />}
/>
);
}
const sample = [
{hero: 'DARTH VADER', faction: 'EMPIRE'},
{hero: 'LUKE SKYWALKER', faction: 'REBEL'},
{hero: 'GREEDO', faction: 'BOUNTY HUNTER'},
];

What's wrong with setting defaultChecked via getCheckboxProps in ant design table selection?

I'm using a table as a radio group. Like this:
<Table
dataSource={keyData}
columns={keyColumns}
rowSelection={keySelection}
pagination={false}
/>
<Form.Item >
{getFieldDecorator('pendingKey', {
initialValue: data?.pendingKey,
rules: [
{
required: type === 'pending_key',
message: 'Select a key'
}
]
})(<div />) // to show eorror message
}
</Form.Item>
Now it really helps to set defaultSelected in getCheckboxProps:
getCheckboxProps: record => ({
defaultChecked: record.key === data?.pendingKey
})
But ant design shows and error message when I do that:
Warning: [antd: Table] Do not set `checked` or `defaultChecked` in `getCheckboxProps`. Please use `selectedRowKeys` instead.
What is exactly wrong with that? How can I keep the input uncontrolled and turn off this message?
Add the selectedRowKeys property in rowSelection to set the selected row
<Table
rowSelection={{
type: 'radio',
selectedRowKeys: ['1'], // Use this attribute
onChange: () => {}
}}
//...Omitting
/>

Resources