Render Name and id Autocomplete material UI - reactjs

i'm working with Autocomplete MUI, i want to render name and id same time in-line but it render name only, can u guys help me, thank you so much
export const zoneUserId = [
{ id: 1, name: 'A' },
{ id: 2, name: 'B' },
];
const listZoneId = {
options: zoneUserId,
getOptionLabel: (option: IZoneID) => option.name,
};
<Autocomplete
{...listZoneId}
id="zoneUserId"
includeInputInList
renderInput={params => (
<TextField {...params} label="User ID" variant="standard" />
)}
/>

You may have to change the getOptionLabel. Either concatenate or try like this
getOptionLabel: (option: IZoneID) => `${option.id} - ${option.name}`

Related

MUI Autocomplete (multiple) controlled values - mysterious input behavior

I am trying to write code to asynchronously search a multiple-select combo upon keyboard entry.
However I found in latest version (5.2.2) a strange behaviour where I cannot explain. I distill the issue below (based on example from MUI's autocomplete page):
import * as React from "react";
import TextField from "#mui/material/TextField";
import Autocomplete from "#mui/material/Autocomplete";
const options = [
{ label: "Option 1", value: 1 },
{ label: "Option 2", value: 2 }
];
export default function ControllableStates() {
// const [value, setValue] = React.useState<any | null>([]);
const value = [];
const [inputValue, setInputValue] = React.useState("");
console.log("Current Value:", value);
return (
<div>
<div>{`value: ${value !== null ? `'${value}'` : "null"}`}</div>
<div>{`inputValue: '${inputValue}'`}</div>
<br />
<Autocomplete
multiple={true}
value={value}
onChange={(event: any, newValue: any | null) => {
//setValue(newValue);
}}
inputValue={inputValue}
onInputChange={(event, newInputValue) => {
setInputValue(newInputValue);
}}
id="controllable-states-demo"
options={options}
sx={{ width: 300 }}
renderInput={(params) => <TextField {...params} label="Controllable" />}
/>
</div>
);
}
The codeSandbox is as follows: https://codesandbox.io/s/controllablestates-material-demo-forked-ygqp2?file=/demo.tsx
If you try in the codeSandbox, you will be unable to type anything in the TextField field.
However, if you switch the commenting:
const [value, setValue] = React.useState<any | null>([]);
// const value = [];
You will be able to type in the TextField field. What is actually happening here? The value did not change at all.
Can anyone figure out why my first code (where the value is a const empty array) didn't work?
The reason I am asking is that I need to pass in the (controlled) value as props, and then set it to default to [] if it is null. I find that I am unable to type in the TextField due to this defaulting.
First, you could use the Autocomplete component without inputValue and OnInputValue props.
...
<Autocomplete
multiple
value={value}
onChange={(event: any, newValue: any | null) => {
//setValue(newValue);
}}
id="controllable-states-demo"
options={options}
sx={{ width: 300 }}
renderInput={(params) => <TextField {...params} label="Controllable" />}
/>
But it won't work for the selection, only search will work.
Second, if you want its search as well as selection to work, then you should use more a couple of Autocomplete props.
...
export default function ControllableStates() {
const [value, setValue] = React.useState<any | null>([]);
// you need to set the selected value your own
// const value = [];
const [inputValue, setInputValue] = React.useState("");
console.log("Current Value:", value);
return (
<div>
<div>{`value: ${value !== null ? `'${value}'` : "null"}`}</div>
<div>{`inputValue: '${inputValue}'`}</div>
<br />
<Autocomplete
multiple
value={value}
onChange={(event: any, newValue: any | null) => {
setValue(newValue.map(option => option.value || option));
}}
isOptionEqualToValue={(option, value) => option.value === value}
getOptionLabel={(option) => {
if (typeof option === 'number') {
return options.find(item => item.value === option)?.label;
} else {
return option.label;
}
}}
id="controllable-states-demo"
options={options}
sx={{ width: 300 }}
renderInput={(params) => <TextField {...params} label="Controllable" />}
/>
</div>
);
}
As you can see it doesn't need to use the inputValue and onInputChange props as well.
Please make sure if you match the correct types of the selected value and option.
If you are using react-hook-form you can set up the autocomplete by using
multiple to add multiple values,
options: you add the options to be selected
getOptionLabel: to show up the label of the options
onChange: use onChange function of react-hook-form to set the selected values
renderInput: to render the input
import { useForm, Controller } from 'react-hook-form'
import {
Box,
TextField,
Autocomplete,
} from '#mui/material'
const {
...
control,
formState: { errors },
} = useForm()
<Box mt={2}>
<Controller
control={control}
name="industries"
rules={{
required: 'Veuillez choisir une réponse',
}}
render={({ field: { onChange } }) => (
<Autocomplete
defaultValue={
useCasesData?.industries
? JSON.parse(useCasesData?.industries)
: []
}
multiple
disableCloseOnSelect
options={companyIndustryTypes}
getOptionLabel={(option) => option.name}
onChange={(event, values) => {
onChange(values)
}}
renderInput={(params) => (
<TextField
{...params}
label="Type d'industries"
placeholder="Type d'industries"
helperText={errors.industries?.message}
error={!!errors.industries}
/>
)}
/>
)}
/>
</Box>
Note that options in my case companyIndustryTypes is an array of object :
[
{
id: 1,
name: "Accounting",
},
{
id: 2,
name: "Administration & Office Support",
},
...
]

How to get dynamically selected value from material ui autocomplete

We can get TextField value dynamically with [evt.target.name]: evt.target.value but
How can I get Autocomplete selected value dynamically, Like bellow example:
import { useState } from 'react'
import Autocomplete from '#mui/material/Autocomplete'
import TextField from '#mui/material/TextField'
import Button from '#mui/material/Button'
const brands = ['niki', 'adidas', 'ramond', 'oliver', 'zara', 'casely']
const categories = ['pant', 'shirt']
const inputItems = [
{ label: 'Product Name', type: 'text', name: 'name' },
{ label: 'Brand', type: 'text', name: 'brand', options: brands },
{ label: 'Category', type: 'text', name: 'category', options: categories },
{ label: 'Price', type: 'number', name: 'price' },
{ label: 'Description', type: 'text', name: 'description' },
{ label: 'Image', type: 'text', name: 'image' },
]
const inputItemsObj = {}
inputItems.forEach(item => inputItemsObj[item.name] = '')
const Products = () => {
const [ fields, setFields ] = useState(inputItemsObj)
const [ fieldsError, setFieldsError ] = useState(inputItemsObj)
const changeHandler = (evt, newValue, action, option ) => {
setFields({ ...fields,[evt.target.name]: evt.target.value })
}
const submitHandler = (evt) => {
evt.preventDefault()
console.log(fields)
}
return (
<form noValidate onSubmit={submitHandler}>
{inputItems.map(({label, type, name, options}, key) => (name === 'category' || name === 'brand') ? (
<Autocomplete key={key}
options={options}
getOptionLabel={option => option}
renderInput={ params => <TextField {...params}
label={label}
placeholder={label}
type={type}
fullWidth
margin='dense'
InputLabelProps={{ shrink: true }}
name={name}
error={!fields[name] || !!fieldsError[name]}
helperText={fieldsError[name]}
/>}
name={name}
value={options[0]}
onChange={changeHandler}
/>
) : (
<TextField key={key}
label={label}
placeholder={label}
type={type}
fullWidth
autoFocus={key === 0}
margin='dense'
InputLabelProps={{ shrink: true }}
name={name}
value={fields[name]}
onChange={changeHandler}
multiline
rows={name === 'description' ? 3 : 1}
error={!fields[name] || !!fieldsError[name]}
helperText={fieldsError[name]}
/>
))}
<Button type='submit' variant='contained' >Submit</Button>
</form>
)
}
export default Products
The second value of onChange will give you a list of all the selected values.
function(event: React.SyntheticEvent, value: T | Array<T>, reason: string, details?: string) => void
So in your example use newValue rather than evt in your changeHandler
More info found here: https://mui.com/api/autocomplete/
Edit: I don't think you will be able to get the name from evt.target.name so some solution like this should work.
const changeHandler = (name) => (evt, newValue, action, option ) => {
// Also as you are updating/adding to state a callback should be used in setFields
setFields((prevState) => ({ ...prevState, [name]: newValue }))
}
Then in the Autocomplete:
<Autocomplete key={key}
//...other props
onChange={changeHandler(name)}
/>

How to use onchange with autocomplete material ui?

With the method handleChange is handled OnChange event of the Form Input with Hooks style that set the state off the object.
The handleChange function in turn calls setLocation which updates the location state with the new value.
To make user data entry easier, I decided to change the city field to an autocomplete, but I failed to capture the value of the autocomplete.
In the documentation he tells me that I need to pass two arguments but I can't understand very well
function(event: object, value: any) => void
event: The event source of the callback
value: null
How can I access the value of the field and put it into my function to insert the data?
<Autocomplete
style={{ width: 300 }}
value={location.City}
onChange={handleChange}
options={list.City}
classes={{
option: classes.option,
}}
autoHighlight
getOptionLabel={option => typeof option === 'string' ? option : option.City}
renderOption={option => (
<React.Fragment>
{option.City} -{option.State}
</React.Fragment>
)}
renderInput={params => (
<TextField {...params} label="City" value={location.City} margin="normal" variant="outlined" style={{ width: 220 }} inputProps={{
...params.inputProps,
autoComplete: 'disabled', // disable autocomplete and autofill
}}/>
)}
/>
If you're just trying to get the value of the input as the user types, you need to use onInputChange. The onChange handler runs when the user selects an option from the drop down.
export default function ComboBox() {
function handleInputChange(event, value) {
console.log(value);
}
return (
<Autocomplete
id="combo-box-demo"
options={top100Films}
getOptionLabel={(option: FilmOptionType) => option.title}
style={{ width: 300 }}
onInputChange={handleInputChange}
renderInput={params => (
<TextField {...params} label="Combo box" variant="outlined" fullWidth />
)}
/>
);
}
Codesandbox
the react SyntheticEvent set null target in an Asynchronous requests, try to use
event.persist()
on the event
https://reactjs.org/docs/events.html#event-pooling
const handleOnChangeText=(event)=> {
event.persist();
console.log(event)
let active = true;
setOpen(true);
if (!loading) {
return undefined;
}
(async () => {
const response = await fetch('https://country.register.gov.uk/records.json?page-size=5000');
await sleep(1e3); // For demo purposes.
const countries = await response.json();
if (active) {
setOptions(Object.keys(countries).map(key => countries[key].item[0]) as CountryType[]);
}
active = false;
})();
}
<Autocomplete
id="comboboxAsync"
disableOpenOnFocus
style={{ width: 300 }}
open={open}
onInputChange={handleOnChangeText}
...
Id is getting retrieved under this pattern: id-option-numberOfOption, that's why I had to split the retrieved value in order to update the state
const handleAutoCompleteChange = (event, value) => {
this.setState({ ...this.state, [event.target.id.split("-")[0]]: value });
console.log([event.target.id.split("-")[0]],value);
}
You can use mui-autocomplete npm its easy and less coding with more options(Like avatar view asynchronus calls).You should try it out. Here is the example for more info visit here.
[http://mui-autocomplete.com/home]
`import React from 'react';
import MuiAutocomplete from 'mui-autocomplete';
const cities = [
{
id: 1,
name: "Alabama",
code: "AL"
},
{
id: 2,
name: "Alaska",
code: "AK"
},
{
id: 3,
name: "American Samoa",
code: "AS"
}];
function Home () {
return (
<div>
<MuiAutocomplete
placeholder="Countries"
name="countries"
setvalue={1}
setdata={cities}
variant="outlined"
template={{
title: 'name'
}}
/>
</div>
);
}`

Handle change on Autocomplete Component from material ui

I want to use Autocomplete component for input tags. I'm trying to get the tags and save them on a state so I can later save them on the database. I'm using functions instead of classes in react. I did try with onChange, but I didn't get any result.
<div style={{ width: 500 }}>
<Autocomplete
multiple
options={autoComplete}
filterSelectedOptions
getOptionLabel={(option) => option.tags}
renderInput={(params) => (
<TextField
className={classes.input}
{...params}
variant="outlined"
placeholder="Favorites"
margin="normal"
fullWidth
/>
)}
/>
</div>;
As Yuki already mentioned, make sure you did use the onChange function properly. It receives two parameters. According to the documentation:
Signature: function(event: object, value: any) => void.
event: The event source of the callback
value: null (The value/values within the Autocomplete component).
Here's an example:
import React from 'react';
import Chip from '#material-ui/core/Chip';
import Autocomplete from '#material-ui/lab/Autocomplete';
import TextField from '#material-ui/core/TextField';
export default class Tags extends React.Component {
constructor(props) {
super(props);
this.state = {
tags: []
};
this.onTagsChange = this.onTagsChange.bind(this);
}
onTagsChange = (event, values) => {
this.setState({
tags: values
}, () => {
// This will output an array of objects
// given by Autocompelte options property.
console.log(this.state.tags);
});
}
render() {
return (
<div style={{ width: 500 }}>
<Autocomplete
multiple
options={top100Films}
getOptionLabel={option => option.title}
defaultValue={[top100Films[13]]}
onChange={this.onTagsChange}
renderInput={params => (
<TextField
{...params}
variant="standard"
label="Multiple values"
placeholder="Favorites"
margin="normal"
fullWidth
/>
)}
/>
</div>
);
}
}
const top100Films = [
{ title: 'The Shawshank Redemption', year: 1994 },
{ title: 'The Godfather', year: 1972 },
{ title: 'The Godfather: Part II', year: 1974 },
{ title: 'The Dark Knight', year: 2008 },
{ title: '12 Angry Men', year: 1957 },
{ title: "Schindler's List", year: 1993 },
{ title: 'Pulp Fiction', year: 1994 },
{ title: 'The Lord of the Rings: The Return of the King', year: 2003 },
{ title: 'The Good, the Bad and the Ugly', year: 1966 },
{ title: 'Fight Club', year: 1999 },
{ title: 'The Lord of the Rings: The Fellowship of the Ring', year: 2001 },
{ title: 'Star Wars: Episode V - The Empire Strikes Back', year: 1980 },
{ title: 'Forrest Gump', year: 1994 },
{ title: 'Inception', year: 2010 },
];
I needed to hit my api on every input change to get my tags from backend!
Use Material-ui onInputChange if you want to get your suggested tags on every input change!
this.state = {
// labels are temp, will change every time on auto complete
labels: [],
// these are the ones which will be send with content
selectedTags: [],
}
}
//to get the value on every input change
onInputChange(event,value){
console.log(value)
//response from api
.then((res) => {
this.setState({
labels: res
})
})
}
//to select input tags
onSelectTag(e, value) {
this.setState({
selectedTags: value
})
}
<Autocomplete
multiple
options={top100Films}
getOptionLabel={option => option.title}
onChange={this.onSelectTag} // click on the show tags
onInputChange={this.onInputChange} //** on every input change hitting my api**
filterSelectedOptions
renderInput={(params) => (
<TextField
{...params}
variant="standard"
label="Multiple values"
placeholder="Favorites"
margin="normal"
fullWidth
/>
Are you sure you used onChange correctly?
onChange signature: function(event: object, value: any) => void
#Dworo
If someone has a problem with displaying a selected item from the dropdown in the Input field,
I found a workaround, basically, you have to bind an inputValue at onChage for both Autocomplete and TextField.
const [input, setInput] = useState('');
<Autocomplete
options={suggestions}
getOptionLabel={(option) => option}
inputValue={input}
onChange={(e,v) => setInput(v)}
style={{ width: 300 }}
renderInput={(params) => (
<TextField {...params} label="Combo box" onChange={({ target }) => setInput(target.value)} variant="outlined" fullWidth />
)}
/>
I wanted to update my state when I select an option from the autocomplete. I had a global onChange handler that manages for all inputs
const {name, value } = event.target;
setTukio({
...tukio,
[name]: value,
});
That updates the object dynamically based on the name of the field. But on the Autocomplete the name returns blank. So I changed the handler from onChange to onSelect. Then either create a separate function to handle the change or as in my case added an if statement to check if the name is not passed.
// This one will set state for my onSelect handler of the autocomplete
if (!name) {
setTukio({
...tukio,
tags: value,
});
} else {
setTukio({
...tukio,
[name]: value,
});
}
The above approach works if u have a single autocomplete. If you have multiple u can pass a custom function like below
<Autocomplete
options={tags}
getOptionLabel={option => option.tagName}
id="tags"
name="tags"
autoComplete
includeInputInList
onSelect={(event) => handleTag(event, 'tags')}
renderInput={(params) => <TextField {...params} hint="koo, ndama nyonya" label="Tags" margin="normal" />}
/>
// The handler
const handleTag = ({ target }, fieldName) => {
const { value } = target;
switch (fieldName) {
case 'tags':
console.log('Value ', value)
// Do your stuff here
break;
default:
}
};
This worked for me:
I have an array of objects of type:
{
id: someId,
label: someLabel,
}
let's call this array "items". And use a formState object, like this:
const [formState, setFormState] = useState({
idPuntoVenta: '',
nomPuntoVenta: '',
selected: items[0],
});
And defined the Autocomplete component like this:
<Autocomplete
disablePortal
id="salesPoint"
options={sortedSalesPoints}
value={selected}
onChange={(event, newValue) => {
setFormState({
...formState,
selected: newValue,
idPuntoVenta: newValue?.id,
});
}}
inputValue={nomPuntoVenta}
onInputChange={(event, newInputValue) => {
setFormState({
...formState,
nomPuntoVenta: newInputValue,
});
}}
renderInput={(params) => (
<TextField
{...params}
className="form-control"
size="small"
label="Punto de venta"
required
/>
)}
/>;
The important thing here (and the one that took me a while) is to understand that the {value} property of the Autocomplete component is an object of the same type of the ones stored in the array "items"

Using react-select with redux form

I am trying to use react-select with redux-form. My code is as follows:
const DropdownComponent = ({
input, options, name, id, placeholder,
}) => (
<Select
id={id}
name={name}
placeholder={placeholder}
value={input.value}
options={options}
onChange={input.onChange}
onBlurResetsInput={false}
onCloseResetsInput={false}
{...input}
onBlur={() => input.onBlur(input.value.value)}
/>
);
The options that I am sending is as:
const options = [
{ value: '1', label: '%' },
{ value: '2', label: '$' },
];
This works fine when I select a value, but the moment the select loses focus, the value is cleared onBlur. Any suggestions as to what am I missing here?
I suspect this maybe the culprit: onBlur={() => input.onBlur(input.value.value)}
I think that extra .value is undefined.

Resources