Autocomplete Material UI search based on two attributes - reactjs

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'},
];

Related

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;
}}

Access selected value from react's Select Component

Hello dear community,
I want to create a very basic website for my school assignment.
I have a dropdown menu with a Select Component as its implementation. I need to access the selected value, which is a currency in my case, in order to update the information displayed on the page once a currency has been selected.
I am kind of frustrated since I wasn't able to find a helpfull solution to my relatively basic problem (I think it's basic :D)
My component class here:
import { Component } from "react";
import Select from 'react-select';
interface DropdownMenuProps {
values: [{}]
defaultValue: string
}
interface DropdownMenuState { }
/**
* Represents a Dropdown Menu
*/
export default class DropdownMenu extends Component<DropdownMenuProps, DropdownMenuState> {
render() {
return (
<div style={{ width: '120px' }}>
<Select id="dropdown-menu"
placeholder={this.props.defaultValue}
options={this.props.values}
// getOptionValue={(option) => option.value}
// getOptionLabel={(option) => option.label}
/>
</div>
)
}
}
This is how I create a dropdown menu compent:
<DropdownMenu defaultValue="Currency" values={[{ label: "EUR", value: "EUR" }, { label: "GBP", value: "GBP" }, { label: "USD", value: "USD" }]} ></DropdownMenu>
I'm glad for any tips :)
You have to use the onChange prop of react-select:
<select
id="dropdown-menu"
onChange={handleSelectChange}
>
and in this function you could handle the changes:
const handleSelectChange = (selectedVal) => console.log(selectedVal)
I recommend you using directly onChange and save it into a state:
1st:
Create state with the name you want:
const [selectValue, setSelectValue] = useState({});
2nd: Create options:
const options = [
{ label: "Tomate", value: 1 },
{ label: "Queso", value: 2 }
];
3rd: add method onChange in select and pass options:
const onChange = (ev) => {
setSelectValue(ev);
//console.log(ev);
console.log(selectValue);
};
<Select
id="dropdown-menu"
placeholder={"e"}
options={options}
onChange={onChange}
/>
I have created demo here:
https://codesandbox.io/s/ancient-pond-96h53?file=/src/App.js

MUI 5 Autocomplete filtered options count

How to get the count of the filtered options from MUI 5 Autocomplete component? (without changing the default behaviour of the prop filterOptions)
You can create a wrapper of filterOptions callback by using createFilterOption to create a default value like the one that is used internally and add your additional code to check for the result length:
import Typography from '#mui/material/Typography';
import TextField from '#mui/material/TextField';
import Autocomplete, { createFilterOptions } from '#mui/material/Autocomplete';
const _filterOptions = createFilterOptions();
export default function ComboBox() {
const [optionCount, setOptionCount] = React.useState(0);
const filterOptions = React.useCallback((options, state) => {
const results = _filterOptions(options, state);
if (optionCount !== results.length) {
setOptionCount(results.length);
}
return results;
}, []);
return (
<>
<Typography mb={2}>Option count: {optionCount}</Typography>
<Autocomplete
filterOptions={filterOptions}
options={top100Films}
sx={{ width: 300 }}
renderInput={(params) => <TextField {...params} label="Movie" />}
/>
</>
);
}
I was using the solution propsed by NearHuscarl and although it worked like a charm, there was this warning from react that kept popping up
Cannot update a component while rendering a different component
So what I did was to use a ref to store the count
const currentViewOptions = useRef(0);
// Instead of: setOptionCount(results.length);
currentViewOptions.current = results.length;
And it worked like a charm. In case anyone comes here with the same problem.

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

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"
/>
)}
/>

Material UI Select Field multiselect

I tried several times the example given in the documentation. but it didn't work well for me.
can any one help me....
this is the code
import React, {Component} from 'react';
import SelectField from 'material-ui/SelectField';
import MenuItem from 'material-ui/MenuItem';
const names = [
'Oliver Hansen',
'Van Henry',
'April Tucker',
'Ralph Hubbard',
'Omar Alexander',
'Carlos Abbott',
'Miriam Wagner',
'Bradley Wilkerson',
'Virginia Andrews',
'Kelly Snyder',
];
/**
* `SelectField` can handle multiple selections. It is enabled with the `multiple` property.
*/
export default class SelectFieldExampleMultiSelect extends Component {
state = {
values: [],
};
handleChange = (event, index, values) => this.setState({values});
menuItems(values) {
return names.map((name) => (
<MenuItem
key={name}
insetChildren={true}
checked={values && values.indexOf(name) > -1}
value={name}
primaryText={name}
/>
));
}
render() {
const {values} = this.state;
return (
<SelectField
multiple={true}
hintText="Select a name"
value={values}
onChange={this.handleChange}
>
{this.menuItems(values)}
</SelectField>
);
}
}
http://www.material-ui.com/#/components/select-field
the select property works but it doesnt select multiple options. when i check the states.value it only includes a single value not a array of values
This example didn't work for me either. To add the multi-select feature you have to manually add the new value to the state, so the handleChange function from the example would look something like this:
handleChange(event, index, values) {
this.setState({
values: [...this.state.values , values]
});
}
EDIT: I updated my version of material-ui to the latest stable version and their example worked like a charm
A much better approach is possible. In the lasted version of material UI.
import Select from '#material-ui/core/Select';
import MenuText from '#material-ui/core/MenuText';
import {useState} from 'react';
const App = () => {
const [selected,setSelected] = useState([]);
return <Select multiple={true} value={selected} onChange={(event) => setSelected(event.target.value)}>
<MenuItem>Val - 1</MenuItem>
<MenuItem>Val - 2</MenuItem>
<MenuItem>Val - 3</MenuItem>
<MenuItem>Val - 4</MenuItem>
</Select>
}
Make sure to set the value of select as an array. Otherwise, It will not work
This worked for me for old material ui version. You can add multiple items and deselect to remove them.
handleChange(event, index, values) {
this.setState({
values: [...values]
});
}

Resources