why checkbox is not checked in react? - javascript

I am trying to implement Auto complete having checkbox.
https://material-ui.com/components/autocomplete/#autocomplete
but when I am implementing same component in final-form I am not able to checked my option why ?
here is my code
https://codesandbox.io/s/relaxed-breeze-hv58o
<Autocomplete
{...rest}
multiple={multiple}
disableCloseOnSelect={true}
options={
multiple
? maxReached
? []
: options.filter(option => !value.includes(option.value))
: options
}
defaultValue={
multiple
? options.filter(option => value.includes(option.value))
: options.find(option => option.value === value)
}
onChange={
multiple
? (_e, values) => {
setMaxReached(value.length >= max - 1);
onChange(values.map(option => option.value));
}
: (_e, option) => onChange(option.value)
}
getOptionLabel={option => option.label}
noOptionsText={
maxReached
? formatMessage({ id: "components.autocomplete.max" }, { max })
: formatMessage({ id: "components.autocomplete.no" })
}
renderOption={(option, { selected }) => (
<React.Fragment>
<Checkbox
icon={icon}
checkedIcon={checkedIcon}
style={{ marginRight: 8 }}
checked={selected}
/>
{option.label}
</React.Fragment>
)}
renderInput={params => (
<TextField
{...params}
{...restInput}
label={label}
placeholder={placeholder || ""}
helperText={
hasError ? formatMessage({ id: error }, { label }) : helperText
}
error={hasError}
fullWidth
/>
)}
/>
);
};

You have some issues with your code (fixed version):
You are calling onChange that makes React-Final-Form re-render, which leads for Autocomplete component to re-render, and remove the select state. To fix this, you will have to use getOptionSelected option.
getOptionSelected={(option, value) => {
return option.value === value.value;
}}
options={
options
}
onChange={(_e, values) => {
onChange(values);
}
You are filtering options based to Autocomplete component, so selected option gets filtered out.
so from this:
options={
multiple
? maxReached
? []
: options.filter(option => !value.includes(option.value))
: options
}
To
options={
options
}

Related

Nextjs React Mui Autocomplete with React Hook Forms and freeSolo

I have a Mui Autocomplete Component with a react-hook-form Controller.
When I set the freeSolo attribute the value doesn't get reset. When I call for example: resetField("selBinvrk") without freeSolo everything works as expected. Here is the code for my autocomplete and the submit function. Can anybody help me with that problem?
<Controller
name={name}
control={control}
rules={rules}
render={({ field: { onChange, value } }) => (
<Autocomplete
disabled={!disabled ? false : true}
value={value}
freeSolo={freeSolo}
//autoSelect={autoSelect}
options={options}
getOptionLabel={getOptionLabel}
isOptionEqualToValue={isOptionEqualToValue}
/* getOptionSelected={(option, value) => {
console.log('get option selected: ', option, value);
return value === undefined || value === "" || option.ID === value.ID}
} */
//console.log(item);
onChange={(event, item) => {
//console.log(item);
onChange(item);
}}
//renderOption={renderOption}
renderInput={(params) => (
<TextField
{...params}
label={label}
variant="outlined"
error={isError}
helperText={errorMessage}
sx={sx}
inputRef={inputRef}
/>
)}
/>
)}
/>
const onSubmit = (data, e) => {
console.log("hä: ", e);
resetField("selBinvrk");
resetField("selMenge");
mutate({
binv_id: data.selBinv.ID,
bsa_id: data.selBinvrk?.BSA_ID || 0,
binvrk_id: data.selBinvrk?.ID || 0,
selMenge: data.selMenge,
bsm_id: data.selBsm.ID,
});
//recaptchaRef.current.execute();
//mutate(data);
};

React - MUI Autocomplete single selection remove event

I use material UI autocomplete to create a single-select dropdown.
But the problem is that when I click the close button placed right-side of the input, the onChange event didn't call and my state didn't update.
While in the multi-select mode this event successfully occurred.
Someone helps me to use the remove event in single-select mode.
This is my single select:
<Autocomplete<Option<T>>
onChange={(e: any, newValue) => {
if (newValue) {
handleChangeValue(newValue.value);
}
}}
sx={{ ...sx }}
id={id}
options={options}
isOptionEqualToValue={(newValue, option) =>
newValue.value === option.value
}
defaultValue={
defaultValue && {
value: defaultValue,
label: options.find((option) => option.value === defaultValue)?.label,
}
}
value={
value && {
value: value,
label: options.find((option) => option.value === value)?.label,
}
}
getOptionLabel={(option) => option.label || `${option.value}`}
renderOption={(props, option, { selected }) => (
<li value={option.value} {...props}>
<Checkbox
style={{ marginRight: 8 }}
checked={selected}
id={`${option.value}`}
/>
{option.label || `${option.value}`}
</li>
)}
renderInput={(params) => (
<TextField
value={value}
{...params}
placeholder={global.translate(placeholder)}
/>
)}
/>
this one is my multi-select autocomplete:
<Autocomplete
onChange={(e: any, value) => {
onChange(value);
}}
value={value}
sx={{ ...sx }}
multiple
id={id}
options={options}
disableCloseOnSelect
defaultValue={[...defaultValues]}
getOptionLabel={(option) => option.label}
isOptionEqualToValue={(newValue, option) =>
newValue.value === option.value
}
renderOption={(props, option, { selected }) => (
<li value={option.value} {...props}>
<Checkbox
icon={<CheckBoxOutlineBlankIcon fontSize="small" />}
checkedIcon={<CheckBoxIcon fontSize="small" />}
style={{ marginRight: 8 }}
checked={selected}
id={option.value}
/>
{option.label}
</li>
)}
renderInput={(params) => (
<TextField {...params} placeholder={placeholder} />
)}
/>
In your single-select mode Autocomplete component, you send handleChangeValue if only newValue exists.
So, in your single-select mode, you need to change this code:
<Autocomplete<Option<T>>
onChange={(e: any, newValue) => {
if (newValue) {
handleChangeValue(newValue.value);
}
}}
to this code:
<Autocomplete<Option<T>>
onChange={(e: any, newValue) => {
const valueToBeSent = newValue ? newValue.value : undefined;
handleChangeValue(valueToBeSent);
}}
in order to send onChange event on every value change.

Warning: Encountered two children with the same key, 'Device 846' in Autocomplete of material-ui [duplicate]

I'm trying to create a Material-UI Autocomplete component that essentially just displays search results to the user. Some of the options' names will be duplicates, but they will all have unique IDs. I receive the following warning:
index.js:1 Warning: Encountered two children with the same key, Name B. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — the behavior is unsupported and could change in a future version.
const SearchField = () => {
const [open, setOpen] = React.useState(false)
const [searchQuery, setSearchQuery] = React.useState('')
const [searchResults, setSearchResults] = React.useState([])
const loading = true //later
const debounced = useDebouncedCallback(
async searchQuery => {
if (searchQuery) {
let result = await doSearch(searchQuery)
if (result.status === 200) {
setSearchResults(result.data)
} else {
console.error(result)
}
}
},
1000
)
const handleInputChange = e => {
if (e.target.value && e.target.value !== searchQuery) {
debounced(e.target.value)
setSearchQuery(e.target.value)
}
}
const options = [{
name: 'Name A',
id: 'entry_0597856'
},{
name: 'Name B',
id: 'entry_3049854'
},{
name: 'Name B',
id: 'entry_3794654'
},{
name: 'Name C',
id: 'entry_9087345'
}]
return (
<Autocomplete
id='search_freesolo'
freeSolo
selectOnFocus
clearOnBlur
handleHomeEndKeys
autoHighlight
onInputChange={handleInputChange}
open={true}
onOpen={() => setOpen(true)}
onClose={() => setOpen(false)}
loading={loading}
key={option => option.id}
options={options}
getOptionLabel={option => option.name}
renderOption={(props, option) => (
<Box
component='li'
{...props}
>
{option.name}
</Box>
)}
renderInput={params => {
return (
<TextField
{...params}
required
id="search_bar"
label="Search"
InputProps={{
...params.InputProps,
endAdornment: (
<React.Fragment>
{loading ? <CircularProgress size={18} /> : null}
{params.InputProps.endAdornment}
</React.Fragment>
)
}}
/>
)}
}
/>
)
}
You can define your own renderOption that can return the list item with a correct key value. Your code complains about the duplicated keys because by default, Autocomplete uses the getOptionLabel(option) to retrieve the key:
<Autocomplete
renderOption={(props, option) => {
return (
<li {...props} key={option.id}>
{option.name}
</li>
);
}}
renderInput={(params) => <TextField {...params} label="Movie" />}
/>
If it still doesn't work, check your props order, you need to declare the key prop last, if you put it before the props provided by the callback:
<Box component='li' key={key} {...props}
Then it will be overridden by the props.key from MUI. It should be like this:
<Box component='li' {...props} key={key}
Live Demo

React Material UI Autocomplete - how to display text name as select but send ID as a value?

MATERUAL UI Autocomplete component works fine, but I want to get object.id as onSelect event value (event.target.value), not the object.name. In other words, I want to display object.name as select item labels, but I want to get object.id as onSelect event value (event.target.value). Right now, my event.target.value is the same as select item label (object.name). Here is an example (from the Material UI documentation):
The options object is like this:
const options = [
{ id: "01", name: "Peter" },
{ id: "02", name: "Mary },
{ id: "03", name: "John" }
]
And the Autocomplete is the same like in Material UI documentation:
<Autocomplete
id="asynchronous-demo"
fullWidth
open={open}
onOpen={() => {
setOpen(true)
}}
onClose={() => {
setOpen(false)
}}
getOptionLabel={(option) => option.name}
options={options}
loading={loading}
renderInput={(params) => (
<TextField
{...params}
label="Asynchronous"
variant="outlined"
onChange={(event) => {
if (event.target.value !== '' || event.target.value !== null) {
onChangeHandle(event.target.value)
}
}}
onSelect={(event) => {
onSelectHandle(event)
}}
InputProps={{
...params.InputProps,
endAdornment: (
<React.Fragment>
{loading ? (
<CircularProgress color="inherit" size={20} />
) : null}
{params.InputProps.endAdornment}
</React.Fragment>
),
}}
/>
)}
/>
With onSelect I always get object.name as event.target.value, but I want to return object.id as event.target.value.
Does anybody knows how??
You are currently grabbing the value from TextField's onSelect, instead of Autocomplete's onChange.
<Autocomplete
...
onChange={(event, newValue) => {
onSelectHandle(newValue)
}}
renderInput={(params) => (
<TextField
{...params}
label="Asynchronous"
variant="outlined"
onChange={(event) => {
if (event.target.value !== '' || event.target.value !== null) {
onChangeHandle(event.target.value)
}
}}
...
/>
)}
/>
For more info, check out the controllable states section in the Autocomplete documentation.

How to control Material-ui <Autocompelete /> by option id

When working with HTML select in React, we tend to use an id or key to track the value selected:
<select value={value} onChange={(event) => setValue(event.target.value)}>
{options.map((option) => (
<option value={option.id}>{option.label}</option>
))}
</select>
I wonder if we can do the same with Material-ui Autocompelete component since in its demo, the value set in state is the whole object instead of the object id.
I tried using its APIs in the following way which make sense to me but it doesn't work as expected:
const fruits = [
{ id: 0, label: "apple" },
{ id: 1, label: "banana" },
{ id: 2, label: "cherries" },
{ id: 3, label: "fig" }
];
function FruitPicker() {
const [value, setValue] = useState(null);
return (
<Autocomplete
id="fruit-picker"
value={value}
onChange={(event, option) => {
setValue(option?.id || null);
}}
options={fruits}
getOptionLabel={(option) => option.label}
getOptionSelected={(option) => option.id === value}
renderInput={(params) => <TextField {...params} label="Fruit" />}
openOnFocus
/>
);
}
I had created this Codesandbox if you want to play around. Thanks.
This is the method that I used.
<Autocomplete
options={fruits}
value={fruits.filter(el => el.id === currentValue)[0]}
getOptionLabel={option => option.label}
onChange={(event, option) => { setValue(option?.id || null); }}
/>
Because you pass the options of array object, so when set value onChange, you must still keep setValue(option), but on getOptionSelected, compare their ids instead
<Autocomplete
value={value}
onChange={(event, option) => {
setValue(option);
}}
options={fruits}
getOptionLabel={(option) => option.label}
getOptionSelected={(option) => option.id === value.id}
renderInput={(params) => <TextField {...params} label="Fruit" />}
openOnFocus
/>

Categories