Material UI Select Multiple Selection in Array - reactjs

I created a Select using React that allows the user to select multiple options.
The problem is that the Select displays the ID of the selected item, instead of their name.
How can I change the code in a way that the Select display the names separated by commas (now shows the IDs separated by commas), while keeping the array of ids for later processing.
Any idea how to fix it? Here is the code to CodeSanbox
I have the following array in a Material UI Select:
const names = [
{ id: "1", value: "Oliver Hansen" },
{ id: "2", value: "Van Henry" },
{ id: "3", value: "Omar Alexander" }
];
This is the code that renders the Multiple Select:
<Select
labelId="demo-mutiple-checkbox-label"
id="demo-mutiple-checkbox"
multiple
value={personName}
name="first"
onChange={handleChange}
input={<OutlinedInput label="Tag" />}
renderValue={(selected) => selected.join(", ")}
>
{names.map((name) => (
<MenuItem key={name.id} value={name.id}>
<Checkbox checked={personName.indexOf(name.id) > -1} />
<ListItemText primary={name.value} />
</MenuItem>
))}
</Select>

I found one possible solution for your issue.
check if it works for you.
import React from "react";
import { makeStyles } from "#material-ui/core/styles";
import { Input, OutlinedInput } from "#material-ui/core";
import InputLabel from "#material-ui/core/InputLabel";
import FormControl from "#material-ui/core/FormControl";
import Select from "#material-ui/core/Select";
import MenuItem from "#material-ui/core/MenuItem";
import ListItemText from "#material-ui/core/ListItemText";
import Checkbox from "#material-ui/core/Checkbox";
const useStyles = makeStyles((theme) => ({
formControl: {
margin: theme.spacing(1),
minWidth: 300
},
selectEmpty: {
marginTop: theme.spacing(2)
}
}));
const names = [
{ id: "1", value: "Oliver Hansen" },
{ id: "2", value: "Van Henry" },
{ id: "3", value: "Van Henry" }
];
export default function NativeSelects() {
const classes = useStyles();
const [personName, setPersonName] = React.useState([]);
const handleChange = (event) => {
const {
target: { value }
} = event;
setPersonName(
// On autofill we get a the stringified value.
typeof value === "string" ? value.split(",") : value
);
};
return (
<div>
<FormControl className={classes.formControl}>
<InputLabel htmlFor="age-native-simple">
Names here to select from
</InputLabel>
<Select
labelId="demo-mutiple-checkbox-label"
id="demo-mutiple-checkbox"
multiple
value={personName}
name="first"
onChange={handleChange}
input={<OutlinedInput label="Tag" />}
renderValue={(selected) => selected.map(obj=> names[obj - 1].value).join(", ")}
>
{names.map((name) => (
<MenuItem key={name.id} value={name.id}>
<Checkbox checked={personName.indexOf(name.id) > -1} />
<ListItemText primary={name.value} />
</MenuItem>
))}
</Select>
</FormControl>
</div>
);
}
Updated Code

just you can do this:
renderValue={
(selected) =>
names.filter( name => selected.includes(name.id) )
.map( record => record.name )
.join(", ")
}

To show the selected user's names, you can update the map part, where currently, you're using id.
You can update this to use the name.value to store/show the person's names.
{names.map((name) => (
<MenuItem key={name.value} value={name.value}>
<Checkbox checked={personName.indexOf(name.value) > -1} />
<ListItemText primary={name.value} />
</MenuItem>
))}
Updated Sandbox

the simple steps I did, just focus on the renderValue property, on the Select component:
renderValue={(selected) => names.find((val) => val.id === selected).value}
the logic I use, find the value in the 'names' array, where the id is the selected id, then take the 'value' value in the 'names' array, to display.

Update the Menu Items' value to be a object instead of an id.
<Select
labelId="demo-mutiple-checkbox-label"
id="demo-mutiple-checkbox"
multiple
value={personName}
name="first"
onChange={handleChange}
input={<OutlinedInput label="Tag" />}
renderValue={(selected) => selected.map((item) => item.value)?.join(",")}
>
{names.map((name) => (
<MenuItem key={name.id} value={name}>
<Checkbox
checked={personName.find((p) => p.id === name.id) !== undefined}
/>
<ListItemText primary={name.value} />
</MenuItem>
))}
</Select>

Related

Dynamic dropdown values are not displaying correctly

I have two antd select fields in a row and a + icon to add another row with two dropdowns as shown in the image.
On click of the first dropdown value, related data should be displayed in dropdown2, and click on + icon it will add two more dropdowns in the second row and respectively and the requirement is the same, onlick of 2nd row first dropdown value. related values will be displayed in the 2nd row 2nd drop-down field.
Issue:
2nd drop-down values are always the same for both rows. When I select the 2nd-row first dropdown value, related values show in 2nd row 2nd dropdown but the same values reflect in the first row second dropdown.
Below my code snippet and I am using antd Form to achieve this. For single row drop-downs it works as expected, but when I add another row by clicking on + icon, an issue occurs. Is there any other approach to implement this?
The code snippet I have added may not work in some environments.
import React, { useRef, useEffect, useState } from "react";
import { Form, Select, Col, Row, Button, Checkbox } from "antd/lib";
import { PlusOutlined, MinusOutlined } from "#ant-design/icons";
const { Option } = Select;
const DropdownComponent = (props) => {
const addBtnRef = useRef(null);
const [dropDownOneData, setDropDownOneData] = useState([]);
const [dropDownTwoData, setDropDownTwoData] = useState([]);
const [dropDownOneValue, setDropDownOneValue] = useState("");
const dropDownOneTwoValues: [
[
{
dropDownOne: {
key: "test_t";
value: "test";
};
dropDownTwo: [
{
key: "key1";
value: "Value1";
},
{
key: "key2";
value: "Value2";
}
];
}
],
[
{
dropDownOne: {
key: "test_t1";
value: "test1";
};
dropDownTwo: [
{
key: "key3";
value: "Value3";
},
{
key: "key4";
value: "Value4";
}
];
}
]
];
useEffect(() => {
addBtnRef.current.click();
// set dropdownone values
const dropDownOneData = dropDownOneTwoValues?.map(
(searchField) => searchField[0].dropDownOne
);
setDropDownOneData(dropDownOneData);
}, []);
useEffect(() => {
// set related dropDownTwo values on selected dropdownOne value
const dropDownTwoValues = dropDownOneTwoValues
.flat()
.filter((values) => values.dropDownOne.key === dropDownOneValue)
.flatMap((value) => value.dropDownTwo);
setDropDownTwoData(dropDownTwoValues);
}, [dropDownOneValue]);
const handleDropDownOne = (value) => {
setDropDownOneValue(value);
};
function renderDropDownValues(options) {
return options.map((option) => {
if (option.key && option.value) {
return (
<Option
key={option.key}
value={option.key}
disabled={option.disabled}
>
{option.value}
</Option>
);
}
return (
<Option key={option} value={option}>
{option}
</Option>
);
});
}
return (
<>
<Row>
<Col>
<Form.List>
{(fields, { add, remove }) => {
{
console.log("fields...", fields);
}
return (
<div
className="border"
style={{
padding: "20px",
marginBottom: "25px",
marginTop: "-30px"
}}
>
{fields.map((value, index) => {
return (
<Row key={index} style={{ marginBottom: 8 }}>
<Col>
<Form.Item
rules={[
{ required: true, message: "Select a value" }
]}
name={value.Name}
>
<Select
key={index}
className="w-100"
showSearch={true}
optionFilterProp="children"
filterOption={(input, option) =>
option?.children
.toLowerCase()
.includes(input.toLowerCase())
}
placeholder="Select"
onChange={(value) => handleDropDownOne(value)}
value={dropDownOneValue}
>
{renderDropDownValues(dropDownOneData)}
</Select>
</Form.Item>
</Col>
<Col>
<Form.Item
rules={[
{ required: true, message: "Select a value" }
]}
name={value.name}
>
<Select
className="w-100"
showSearch={true}
optionFilterProp="children"
filterOption={(input, option) =>
option?.children
.toLowerCase()
.includes(input.toLowerCase())
}
placeholder="Select"
>
{renderDropDownValues(dropDownTwoData)}
</Select>
</Form.Item>
</Col>
</Row>
);
})}
<Row justify="end">
<Col>
<Form.Item>
<Button
ref={addBtnRef}
shape="circle"
size="small"
className="center"
data-testid="add-clause-btn"
icon={
<PlusOutlined
className="primary-color"
style={{ marginTop: "1px" }}
/>
}
onClick={() => {
add();
}}
/>
</Form.Item>
</Col>
</Row>
</div>
);
}}
</Form.List>
)
</Col>
</Row>
</>
);
};
export default DropdownComponent;
You need to have unique Form.Item name for every row.
Try this,
name={[index, value.Name]}
and provide a name for Form.List also, name={"something"}

Unable to Select options from select component using material ui react

I'm working on material ui react storybook . I have given customised select options but when i select options it is not selecting. Below is what i have tried if option 1 is selected it not taking any value. How do i select options ? I cannot use TextField , because i'm working on select component. I have to achieve this with the Mapping. Thanks. Below is My code.
export const SelectBasic= ({
props,
selectoptions,
}) => {
const theme = useTheme();
const [age, setAge] = React.useState('');
const handleChange = (event: SelectChangeEvent) => {
setAge(event.target.valueasstring);
};
return (
<div>
<FormControl fullWidth >
<InputLabel id="demo-simple-select-label">Age</InputLabel>
<Select
labelId="demo-simple-select-label"
id="demo-simple-select"
value={age}
label="Age"
onChange={handleChange}
>
{selectoptions.map(item => {
return (
<MenuItem value={item.label}>{item.label}</MenuItem>
)
})}
</Select>
</FormControl>
</div >
);
}
stories.js
export const Selectdef = SelectBasic.bind({});
Selectdef .args = {
selectoptions: [{ "label": "Option 1" }, { "label": "Option 2" }, { "label": "Option 3" }],
};
const {
Box,
FormControl,
InputLabel,
MenuItem,
Select,
Typography
} = MaterialUI;
const OPTIONS = [{
value: 10,
label: 'ten'
},
{
value: 20,
label: 'twenty'
},
{
value: 30,
label: 'thirty'
}
];
const BasicSelect = ({options}) => {
const [age, setAge] = React.useState('');
const handleChange = (event) => {
setAge(event.target.value);
};
return (
<Box sx={{ minWidth: 120 }}>
<FormControl fullWidth>
<InputLabel id="demo-simple-select-label">Age</InputLabel>
<Select
labelId="demo-simple-select-label"
id="demo-simple-select"
value={age}
label="Age"
onChange={handleChange}
>
{options.map(item => <MenuItem value={item.value}>{item.label}</MenuItem>)}
</Select>
</FormControl>
<Typography>{`Currently selecting: ${age || 'undefined'}`}</Typography>
</Box>
);
}
ReactDOM.render( <BasicSelect options={OPTIONS} / > ,
document.getElementById("root")
);
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/#mui/material#latest/umd/material-ui.production.min.js"></script>
In your onChange function where you set state.
const handleChange = (event: SelectChangeEvent) => {
setAge(event.target.valueasstring);
};
`event.target.value` should be sent to `setAge`.
There are some code style issues but this is what breaks the option selection.
Your map placement is incorrect and you are missing to set a value for the MenuItem
Try this:
return (
<div>
<FormControl fullWidth >
<InputLabel id="demo-simple-select-label">Age</InputLabel>
<Select
labelId="demo-simple-select-label"
id="demo-simple-select"
value={age}
label="Age"
onChange={handleChange}
>
{selectoptions.map((item) => {
return(
<MenuItem value={item.label}>{item.label}</MenuItem>
)
})}
</Select>
</FormControl>
</div >
);

Unable to dynamically set the initial state of a Select box in Material UI

I'm using Material UI 5.7.0. I've created a survey form that users can fill out and click a button to download a json file with their answers. I'd like to manage my questions in json object called questionsObject. It seemed to make sense to use this same object (or one created dynamically from it) to load the initial state of the form as well as updating it.
The below code is working BUT I've statically defined my default values in the defaultValues object. I'll need to update that every time I add a new question to the questions object. I really want it to read the default value from the value field in the questionsObject.
Working code
import React, {useEffect, useState} from "react";
import Grid from "#mui/material/Grid";
import FormControlLabel from "#mui/material/FormControlLabel";
import FormControl from "#mui/material/FormControl";
import FormLabel from "#mui/material/FormLabel";
import RadioGroup from "#mui/material/RadioGroup";
import Radio from "#mui/material/Radio";
import Button from "#mui/material/Button";
import Select from '#mui/material/Select';
import { saveAs } from 'file-saver';
import {InputLabel, MenuItem} from "#mui/material";
const questionsObject = {
q1: {
questionText: "Animals",
type: "BOTH",
displayType: "select",
menuItems: [
'',
"Dogs",
"Cats",
"Elephants"
],
value: ''
},
q2: {
questionText: "Favorite Pizza Topping",
type: "BOTH",
displayType: "select",
menuItems: [
'',
"Pepperoni",
"Mushrooms"
],
value: ''
},
q3: {
questionText: "Question text",
type: "BOTH",
displayType: "radioGroup",
value: "true"
},
q4: {
questionText: "Question text",
type: "BOTH",
displayType: "radioGroup",
value: "no answer"
},
q5: {
questionText: "Question text",
type: "BE",
displayType: "radioGroup",
value: "no answer"
}
}
const defaultValues = {
q1: '',
q2: '',
q3: "no answer",
q4: "no answer",
q5: "no answer"
}
const MyForm = () => {
const [formValues, setFormValues] = useState(defaultValues);
// useEffect(() => {
// const outputObj = {}
// Object.keys(questionsObject).map((question) =>
// outputObj[question.id] = question.value
// );
// setFormValues(outputObj)
// }, []);
const handleInputChange = (e) => {
const { name, value} = e.target;
setFormValues({
...formValues,
[name]: value
});
};
const handleSubmit = (event) => {
event.preventDefault();
const outputObj = {}
Object.keys(questionsObject).map((question) =>
outputObj[question.id] = {
questionText: question.questionText,
type: question.type,
answer: formValues[question.id]
}
);
console.log(outputObj);
const outputObjJSON = JSON.stringify(outputObj, null, 2);
const blob = new Blob([outputObjJSON], {type: "application/json"});
saveAs(blob, "answerfile.json");
};
const getQuestionElement = (questionId) => {
const question = questionsObject[questionId];
switch(question.displayType) {
case "radioGroup":
return (
<Grid item key={questionId}>
<FormControl>
<FormLabel>{question.questionText}</FormLabel>
<RadioGroup
questiontype = {question.type}
name={questionId}
value={formValues[questionId]}
onChange={handleInputChange}
row
>
<FormControlLabel
value="no answer"
control={<Radio size="small" />}
label="No Answer"
/>
<FormControlLabel
value="false"
control={<Radio size="small" />}
label="False"
/>
<FormControlLabel
value="true"
control={<Radio size="small" />}
label="True"
/>
<FormControlLabel
value="NA"
control={<Radio size="small" />}
label="Not Applicable"
/>
</RadioGroup>
</FormControl>
</Grid>
);
case "select":
return (
<Grid item key={questionId}>
<FormControl sx={{ m: 2, minWidth: 200 }}>
<InputLabel>{question.questionText}</InputLabel>
<Select
name={questionId}
value={formValues[questionId]}
label={question.questionText}
onChange={handleInputChange}
>
{question.menuItems.map((item, index) =>
<MenuItem key={index} value={item}>{item}</MenuItem>
)}
</Select>
</FormControl>
</Grid>
);
default:
}
}
return formValues ? (
<form onSubmit={handleSubmit}>
<Grid
container
spacing={0}
direction="column"
alignItems="left"
justifyContent="center">
{Object.keys(questionsObject).map((questionId =>
getQuestionElement(questionId)
))}
<Button variant="contained" color="primary" type="submit">
Download
</Button>
</Grid>
</form>
): null ;
};
export default MyForm;
Things I've tried
I tried starting with no default state like this:
const [formValues, setFormValues] = useState();
and uncommenting useEffect()
but I get this error:
MUI: You have provided an out-of-range value `undefined` for the select component.
Consider providing a value that matches one of the available options or ''.
The available values are ``, `Dogs`, `Cats`, `Elephants`.
on top of that my Radio Buttons have no default value set.
This lead me to attempting to use the defaultValue fields on both the RadioGroup and the Select component.
Attempting to set initial values in the defaultValue property like this:
defaultValue=""
or
defaultValue={question.value}
Give me this error:
MUI: A component is changing the uncontrolled value state of Select to be controlled.
Elements should not switch from uncontrolled to controlled (or vice versa).
Decide between using a controlled or uncontrolled Select element for the lifetime of the component.
The nature of the state is determined during the first render. It's considered controlled if the value is not `undefined`.
How can I remove the defaultValues object and use the value field inside of questionsObject for the initial state instead?
The problem is in the logic inside your useEffect:
useEffect(() => {
const outputObj = {}
Object.keys(questionsObject).map(
(question) => outputObj[question.id] = question.value
);
console.log(outputObj);
setFormValues(outputObj)
}, []);
/// OUTPUT of outputObj:
{undefined: undefined}
You should change it to:
useEffect(() => {
const outputObj = {};
Object.keys(questionsObject).map(
(question) => (outputObj[question] = questionsObject[question].value)
);
console.log(outputObj);
setFormValues(outputObj);
}, []);
/// OUTPUT of outputObj:
{q1: "", q2: "", q3: "true", q4: "no answer", q5: "no answer"}
Also, avoid the switch/case - mainly for not doing anything with default value. In this case prefer the conditional renderering with && operator (docs):
const getQuestionElement = (questionId) => {
const question = questionsObject[questionId];
return (
<React.Fragment key={questionId}>
{question.displayType === "radioGroup" && (
<Grid item>
<FormControl>
<FormLabel>{question.questionText}</FormLabel>
<RadioGroup
questiontype={question.type}
name={questionId}
value={formValues[questionId]}
onChange={handleInputChange}
row
>
<FormControlLabel
value="no answer"
control={<Radio size="small" />}
label="No Answer"
/>
<FormControlLabel
value="false"
control={<Radio size="small" />}
label="False"
/>
<FormControlLabel
value="true"
control={<Radio size="small" />}
label="True"
/>
<FormControlLabel
value="NA"
control={<Radio size="small" />}
label="Not Applicable"
/>
</RadioGroup>
</FormControl>
</Grid>
)}
{question.displayType === "select" && (
<Grid item>
<FormControl sx={{ m: 2, minWidth: 200 }}>
<InputLabel>{question.questionText}</InputLabel>
<Select
name={questionId}
value={formValues[questionId]}
label={question.questionText}
onChange={handleInputChange}
>
{question.menuItems.map((item, index) => (
<MenuItem key={index} value={item}>
{item}
</MenuItem>
))}
</Select>
</FormControl>
</Grid>
)}
</React.Fragment>
);
};

How to use MUI Select with react-hook-form?

I've built a form in React using MUI and React Hook Form. I'm trying to create a custom TextField element that works as a Select Input. I would like it to be an uncontrolled component with a Ref prop. I've tried to pass the inputRef prop as the MUI and React Hook Form docs recommend but with no success.
<TextField
id="id"
name="name"
select
native="true"
className={classes.textField}
label="label"
margin="normal"
variant="outlined"
inputRef={register({ required: "Choose one option" })}
error={!!errors.name}
>
<MenuItem value="">Choose one option</MenuItem>
<MenuItem value="3">03</MenuItem>
<MenuItem value="6">06</MenuItem>
<MenuItem value="9">09</MenuItem>
<MenuItem value="12">12</MenuItem>
<MenuItem value="16">16</MenuItem>
<MenuItem value="18">18</MenuItem>
</TextField>
One thing that I've found is that if I use the native select with ref, it works just fine.
Besides, I tried to change the inputRef prop to a SelectProps one but it didn't work too.
Using Select component from Material-ui with react hook form need you to implement custom logic with a Controller https://react-hook-form.com/api#Controller
Here is a reusable component that will hopefully simplify the code to use that Select component in your app:
import FormControl from "#material-ui/core/FormControl";
import InputLabel from "#material-ui/core/InputLabel";
import Select from "#material-ui/core/Select";
import { Controller } from "react-hook-form";
const ReactHookFormSelect = ({
name,
label,
control,
defaultValue,
children,
...props
}) => {
const labelId = `${name}-label`;
return (
<FormControl {...props}>
<InputLabel id={labelId}>{label}</InputLabel>
<Controller
as={
<Select labelId={labelId} label={label}>
{children}
</Select>
}
name={name}
control={control}
defaultValue={defaultValue}
/>
</FormControl>
);
};
export default ReactHookFormSelect;
You can use it in your app like this:
<ReactHookFormSelect
id="numero_prestacao"
name="numero_prestacao"
className={classes.textField}
label="Em quantas parcelas?"
control={control}
defaultValue={numero_prestacao || ""}
variant="outlined"
margin="normal"
>
<MenuItem value="">Escolha uma opção</MenuItem>
<MenuItem value="3">03 parcelas</MenuItem>
<MenuItem value="6">06 parcelas</MenuItem>
<MenuItem value="9">09 parcelas</MenuItem>
<MenuItem value="12">12 parcelas</MenuItem>
<MenuItem value="16">16 parcelas</MenuItem>
<MenuItem value="18">18 parcelas</MenuItem>
</ReactHookFormSelect>
Here is your codeSandBox updated with this component for the selects in the Information form:
https://codesandbox.io/s/unit-multi-step-form-kgic4?file=/src/Register/Information.jsx:4406-5238
RHF v7 update
Below is a minimal code example of MUI Select in a RHF form:
const { formState, getValues, watch, register, handleSubmit } = useForm();
const { errors } = formState;
<TextField
select
fullWidth
label="Select"
defaultValue=''
inputProps={register('currency', {
required: 'Please enter currency',
})}
error={errors.currency}
helperText={errors.currency?.message}
>
{currencies.map((option) => (
<MenuItem key={option.value} value={option.value}>
{option.label}
</MenuItem>
))}
</TextField>
Accepted version is correct but outdated.
At least in the version that I'm using: "react-hook-form": "^7.30.0" you should use the render parameter.
Here is the "updated" version that perfectly works for me:
<FormControl>
<InputLabel id="level-label">Level</InputLabel>
<Controller
name="level"
id="level"
defaultValue={level}
control={control}
render={({ field }) => (
<Select labelId="level-label" {...field}>
<MenuItem value={0}>0</MenuItem>
<MenuItem value={1}>1</MenuItem>
</Select>
)}
/>
<FormHelperText error={true}>{errors.level?.message}</FormHelperText>
</FormControl>
The important here is to propagate the field properties down to the child element (Select in our case)
PS. I don't think you need a separate component for it, it is pretty straight forward.
[Updated]
Here is a full code of one of my dialog. As per request from Deshan.
import {
Box, Chip, FormControl, Input, Stack,
} from '#mui/material';
import { useCallback, useEffect, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import PropTypes from 'prop-types';
import { Link } from 'react-router-dom';
import debounce from '../#utils/debounce';
import useRawParams from '../#utils/useRawParams';
import { useBrandsSearchQuery } from '../data/products';
import { SearchRoute } from '../SBRoutes';
import LoadingDiv from './LoadingDiv';
import SBDialog from './SBDialog';
import { useSearchBarContext } from '../contexts/SearchBarContext';
const context = { suspense: false };
/**
* Show the modal dialog with the list of brands, and search box for it
* Eeach brand will be as a link, for the SEO purposes
*/
export default function AllBrandsDialog({ open, setOpen }) {
const [t] = useTranslation();
const [query, setQuery] = useState('');
const [brands, setBrands] = useState([]);
const params = useRawParams(true);
const paramsBrands = params.brands?.split(',') || [];
const { setFilterActive } = useSearchBarContext();
const variables = useMemo(() => (query.length ? {
filterText: query,
} : null), [query]);
const [{ data, fetching: loading }] = useBrandsSearchQuery({ variables, pause: Boolean(!variables), context });
const debounceSetQuery = useCallback(debounce(200, (text) => {
setQuery(text);
}));
useEffect(() => {
if (!data || !open) return;
setBrands(data.brands || []);
}, [data, open]);
return (
<SBDialog open={open} setOpen={setOpen} title={t('Search and select a brand')}>
<Stack direction="column" spacing={2}>
<FormControl>
<Input
id="tagSearch"
placeholder={t('Start typing to see the brands')}
onChange={(e) => debounceSetQuery(e.target.value)}
autoFocus={true}
/>
</FormControl>
<Box display="grid" width={220} height={300} overflow="auto" gap={1} position="relative">
{brands?.map((brand) => (
<Chip
component={Link}
key={brand.id}
disabled={paramsBrands.indexOf(brand.url) > -1}
to={SearchRoute.generatePath({
...params,
brands: [...paramsBrands, brand.url],
page: undefined,
})}
size="small"
label={brand.nicename}
variant="outlined"
onClick={() => {
setOpen(false);
setFilterActive(false);
}}
clickable={true}
/>
))}
{loading && <LoadingDiv modal={true} />}
</Box>
</Stack>
</SBDialog>
);
}
AllBrandsDialog.propTypes = {
open: PropTypes.bool.isRequired,
setOpen: PropTypes.func.isRequired,
};
Here my code that working, hope it can help, need to use setValue
<TextField
fullWidth
inputRef={register({
name: 'name',
})}
select
onChange={e => setValue('name', e.target.value, true)}
label={label}
defaultValue={defaultValue}
>
{options.map((option) => (
<MenuItem key={option.label} value={option.value}>
{option.label}
</MenuItem>
))}
</TextField>
Here using native select, do not need setValue, but value alway string
<TextField
fullWidth
select
SelectProps={{
native: true,
inputProps: { ref: register, name: 'name' }
}}
label={label}
defaultValue={defaultValue}
>
{options.map((option) => (
<option key={option.label} value={option.value}>
{option.label}
</option>
))}
</TextField>
This is an example that uses Material-UI with React hook form. You need to add the validation in 'inputRef' prop of TextField. Also you need to add 'onChange' function to keep the state updated. 'shouldValidate' will trigger the validation.
<TextField
select
name='city'
inputRef={register({ required: true })}
onChange={e => setValue('city', e.target.value, { shouldValidate: true })}
label="City"
defaultValue="">
{cityList.map((option, index) => (
<MenuItem key={index} value={option}>
{option}
</MenuItem>
))}
</TextField>
{errors.city && <ErrorText>City is required</ErrorText>}
✔ I came across this same issue, and this is how i solved mine:
<Select ... onChange={e => register({ name: 'academicLevel', value: e.target.value })}/>
more info
When you using react-hook-form with material UI, you don´t need to use onChange and setState. Only use inputRef and all works!
Just need to pass the register to the Input Ref
<Select
variant="outlined"
name="reason"
inputRef={register({ required: true })}
>
just use mui-react-hook-form-plus
Here is an example:
import { HookSelect, useHookForm } from 'mui-react-hook-form-plus';
const defaultValues = {
person: {
firstName: 'Atif',
lastName: 'Aslam',
sex: '',
},
};
const App = () => {
const { registerState, handleSubmit } = useHookForm({
defaultValues,
});
const onSubmit = (_data: typeof defaultValues) => {
alert(jsonStringify(_data));
};
return (
<HookSelect
{...registerState('person.sex')}
label='SEX'
items={[
{ label: 'MALE', value: 'male' },
{ label: 'FEMALE', value: 'female' },
{ label: 'OTHERS', value: 'others' },
]}
/>
)
}
Repo: https://github.com/adiathasan/mui-react-hook-form-plus
Demo: https://mui-react-hook-form-plus.vercel.app/?path=/docs/

Material ui list of select item need to be selected

i have created selected box..using functional component...i am getting list of items from the back end, i am looping that list and showing in the front end....now i need to be selected item need to show in the box what i have selected...could any one help on this...
Please see my example code in this link https://codesandbox.io/s/gallant-water-fnqiv
import React from "react";
import { makeStyles } from "#material-ui/core/styles";
import InputLabel from "#material-ui/core/InputLabel";
import MenuItem from "#material-ui/core/MenuItem";
import FormControl from "#material-ui/core/FormControl";
import Select from "#material-ui/core/Select";
const useStyles = makeStyles(theme => ({
formControl: {
margin: theme.spacing(1),
minWidth: 120
},
selectEmpty: {
marginTop: theme.spacing(2)
}
}));
const lists = ["Ten", "twenty", "Thirty", "Fourty", "Fifity", "Sixty"];
export default function SimpleSelect() {
const classes = useStyles();
const [age, setAge] = React.useState("");
const inputLabel = React.useRef(null);
const [labelWidth, setLabelWidth] = React.useState(0);
React.useEffect(() => {
setLabelWidth(inputLabel.current.offsetWidth);
}, []);
const handleChange = event => {
setAge(event.target.value);
};
return (
<div>
<FormControl variant="outlined" className={classes.formControl}>
<InputLabel ref={inputLabel} id="demo-simple-select-outlined-label">
Age
</InputLabel>
<Select
labelId="demo-simple-select-outlined-label"
id="demo-simple-select-outlined"
value={age}
onChange={handleChange}
labelWidth={labelWidth}
>
<MenuItem value={""}>
{lists.map(item => {
<li>{item.list}</li>;
})}
</MenuItem>
</Select>
</FormControl>
</div>
);
}
There is no property in the array named, item.list , so you need to use item alone which itself gives the value you want.
Also make sure <MenuItem value={item}> is inside the lists.map() method..
Include return statement of the MenuItemis inside ofthe lists.map() method which throws error in your codesandbox link
And hence,
Change:
<MenuItem value={""}>
{lists.map(item => {
<li>{item.list}</li>;
})}
</MenuItem>
To:
{lists.map(item => {
return (
<MenuItem value={item}>
<li>{item}</li>
</MenuItem>
);
})}
Forked Codesandbox
you can try this-
<div>
<FormControl variant="outlined" className={classes.formControl}>
<InputLabel ref={inputLabel} id="demo-simple-select-outlined-label">
Age
</InputLabel>
<Select
labelId="demo-simple-select-outlined-label"
id="demo-simple-select-outlined"
value={age}
onChange={handleChange}
labelWidth={labelWidth}
>
{lists.map(item => (
<MenuItem value={item}>{item}</MenuItem>
))}
</Select>
</FormControl>
</div>
https://codesandbox.io/s/material-ui-select-m8lgt
Updated code sandbox link
Your MenuItem was wrong.
{lists.map(item => (
<MenuItem value={item}>{item}</MenuItem>
))}

Resources