Binding initial value to material ui select - reactjs

I am using material ui in my react application.
And I am using select component.
I want to bind some initial values to the select control.
I had tried with the useState hook. It's not working.
Below is the code i am using.
const userContributors=[{
firstName: "user101",
id: "1",
role: "Users"
},{
firstName: "user102",
id: "2",
role: "Users"
},{
firstName: "user103",
id: "3",
role: "Users"
}]
const [ApplicationAdminUsers, SetApplicationAdminUsers] = useState([
{
firstName: "user101",
id: "1",
role: "Users"
}
]);
<FormControl
variant="outlined"
margin="normal"
InputLabelProps={{
shrink: true
}}
validators={["required"]}
errorMessages={["Select Application Admin"]}
className={[
classes.formControl,
"fullWidthControl",
"multiselect-checkbox"
].join(" ")}
>
<InputLabel
ref={inputLabel}
htmlFor="select-multiple-checkbox"
className="multi-label-top"
>
Select Users...
</InputLabel>
<Select
multiple
value={ApplicationAdminUsers}
onChange={handleChangeUserContributores}
className="multi-input-padding"
validators={["required"]}
errorMessages={["Select Application Admin"]}
input={
<OutlinedInput
labelWidth={labelWidth}
id="select-multiple-checkbox"
/>
}
MenuProps={MenuProps}
>
{userContributors.map((item, index) => (
<MenuItem key={"aa" + item.id} value={item}>
{item.firstName}
</MenuItem>
))}
</Select>
</FormControl>
And here I'm using this as multi select control.
Any solutions to solve this.
Thanks

When you're using object as material-ui Select value, you need to provide 'renderValue' prop:
renderValue={selected => selected.map(item => item.firstName).join(', ')}
You can refer to this CodeSandbox example

You can't use an object as the value for the input, it needs to be a string.
Also you haven't handled the onChange to update the array to add/remove items.
As a simple example.
const userContributors=["joe", "bob", "tim"]
...
const [ApplicationAdminUsers, SetApplicationAdminUsers] = useState(["joe"]);
...
<Select
multiple
value={ApplicationAdminUsers}
onChange={(event)=> SetApplicationAdminUsers(event.target.value)}
className="multi-input-padding"
validators={["required"]}
errorMessages={["Select Application Admin"]}
input={
<OutlinedInput
labelWidth={labelWidth}
id="select-multiple-checkbox"
/>
}
MenuProps={MenuProps}
>

Related

How to set value in MUI Select on onChange in Formik?

I was facing some challenges while integrating Formik with the Select component of MUI, firstly, it didn't change the value on the onChange event and also was not showing any error messages , if I didn't select anything, so at last, I was able to find the solution and I have shared the answer below
Here, I am setting the value directly using formik.setFieldValue and passing the value to as we usually do, also to show error messages I have used FormHelperText from MUI
const formik = useFormik({
initialValues: {
user: '',
},
validationSchema: validationSchema,
onSubmit: (values) => {
alert(JSON.stringify(values, null, 2));
},
});
------------
<FormControl
fullWidth
size="small"
id="userType"
error={formik.touched.userType && Boolean(formik.errors.userType)}
>
<InputLabel id="user-type">User Type</InputLabel>
<Select
id="userType"
label="User Type"
name="userType"
value={formik.values.userType}
onBlur={formik.handleBlur}
onChange={(e) => formik.setFieldValue('userType', e.target.value as string)}
error={formik.touched.userType && Boolean(formik.errors.userType)}
>
<MenuItem value={'admin'}>Student</MenuItem>
<MenuItem value={'superAdmin'}>Recruiter</MenuItem>
</Select>
{formik.touched.password && (
<FormHelperText sx={{ color: 'error.main' }}>{formik.errors.userType}</FormHelperText>
)}
</FormControl>

set initalValues in nested dynamic form | Antd

I've created the sandbox below hoping someone can help me.
https://codesandbox.io/s/suspicious-leaf-cijswt?file=/src/App.js
What I need to do is basically load the ingredients array as initialValues of Form.List.
Is that possible? If yes, how?
I'd really appreciate any help.
Thanks!
Use initialValues prop in Form to initialize fields. Since you named your FormList as users. You can set the values like this:
initialValues={{ users: ingredients }}
Now your field looks like this:
<Form.Item
{...restField}
name={[name, "first"]}
rules={[{ required: true, message: "Missing first name" }]}
>
<Input placeholder="First Name" />
</Form.Item>
The most thing is the name attribute name={[name, "first"]}. In ingredients array, each object have the following keys: key, id, & amount. Suppose you want to show id & amount in each input. You specify the field path using [name, "id"]. where name presents the index of array & id is the key of object in an array. Antd will automatically get the value if it's available in that array.
I just make few changes changes like proper naming keys,... according to the data
Complete Code
import { Form, Input, Button, Space, InputNumber } from 'antd';
import { MinusCircleOutlined, PlusOutlined } from '#ant-design/icons';
const ingredients = [
{
key: 0,
name: 'Wheat Flour',
amount: 1000
},
{
key: 1,
name: 'Sugar',
amount: 800
}
];
export default function App() {
return (
<Space style={{ display: 'flex', margin: 36 }} align='baseline'>
<Form
name='dynamic_form_nest_item'
onFinish={console.log}
autoComplete='off'
initialValues={{ ingredients: ingredients }}
>
<Form.List name='ingredients'>
{(fields, { add, remove }) => (
<>
{fields.map(({ key, name, ...restField }) => (
<Space key={key} style={{ display: 'flex', marginBottom: 8 }} align='baseline'>
<Form.Item
{...restField}
name={[name, 'name']}
rules={[{ required: true, message: 'Missing ingredient' }]}
>
<Input placeholder='Ingredient' />
</Form.Item>
<Form.Item
{...restField}
name={[name, 'amount']}
rules={[{ required: true, message: 'Missing Amount' }]}
>
<InputNumber placeholder='Amount' />
</Form.Item>
<MinusCircleOutlined onClick={() => remove(name)} />
</Space>
))}
<Form.Item>
<Button type='dashed' onClick={() => add()} block icon={<PlusOutlined />}>
Add field
</Button>
</Form.Item>
</>
)}
</Form.List>
<Form.Item>
<Button type='primary' htmlType='submit'>
Submit
</Button>
</Form.Item>
</Form>
</Space>
);
}

Material UI Select Multiple Selection in Array

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>

Adding Select All in Material UI multiselect and displaying the values in select option

I'm new to Material UI and trying to integrate a select all option in material multiselect.
I have a array of object
const names = [
{ id: 0, name: "Oliver Hansen" },
{ id: 1, name: "Van Henry" },
{ id: 2, name: "April Tucker" }
];
I'm iterating over this array and displaying the value in multiselect.
Below is the code for Multiselect
<FormControl className={classes.formControl}>
<InputLabel id="demo-mutiple-checkbox-label">Tag</InputLabel>
<Select
labelId="demo-mutiple-checkbox-label"
id="demo-mutiple-checkbox"
multiple
value={personName}
onChange={handleChange}
input={<Input />}
renderValue={(selected) => selected.join(", ")}
MenuProps={MenuProps}
>
<MenuItem
value="all"
classes={{
root: isAllSelected ? classes.selectedAll : ""
}}
>
<ListItemIcon>
<Checkbox
classes={{ indeterminate: classes.indeterminateColor }}
checked={isAllSelected}
indeterminate={
personName.length > 0 && personName.length < names.length
}
/>
</ListItemIcon>
<ListItemText
classes={{ primary: classes.selectAllText }}
primary="Select All"
/>
</MenuItem>
{names.map((item, index) => (
<MenuItem key={item.id} value={item.id}>
<Checkbox checked={personName.indexOf(item.id) > -1} />
<ListItemText primary={item.name} />
</MenuItem>
))}
</Select>
</FormControl>
In the select option i'm giving value as id and text as name, But when i select any option it will display me the value in place of name.
Which is correct in one sense but i want to display only name in the select field not its id which i associated to the value.
Also selectAll is acting as a indiviual option not selection all the values.
Here is the sandbox link
If you have id you can find object which belongs to it and then use only the name.
renderValue={
(selected) =>
names.filter( name => selected.includes(name.id) )
.map( record => record.name )
.join(", ")
}

how to delete the formik values using field array

how can we delete the formik values when using field arrays .So Its gets
deleted from the UI when I delete it , but stays in the formik values.
can I edit/modify formik values directly ?
I am new to react here. Thanks
{
Client:
Phone: [
{
PhoneNumber:"",
PhoneType:""
}
]
}
I am able to delete the occurrence from the state, but formik values still retains the values.
const Phone = ({ title, binding }) => {
const [phones, setPhones] = useState([])
return (
<Fragment>
<Grid item xs={12} md={6}>
<SectionField
title={title}
name={binding + `.Phone.PhoneNumber`}
required
label="Phone"
fullWidth
type="tel"
component={TextField}
/>
</Grid>
<Grid item xs={12} sm={3}>
<SectionField
title={title}
name={binding + `.Phone.PhoneType`}
required
defaultValue={{ label: "", value: "" }}
label="Phone Type"
suggestions={phoneTypes}
component={MuiReactSelect}
/>
</Grid>
<IconButton onClick={() => {
setPhones(currentValue => [...currentValue, {
id: generate(),
PhoneNumber: "",
PhoneType: ""
}])
}}>
<AddBoxIcon fontSize="large" />
</IconButton>
{phones.map((p, index) => (
<Fragment key={p.id}>
<Grid item xs={12} md={5}>
<SectionField
title={title}
name={binding + `.Phone[${index}].PhoneNumber`}
required
label="Phone"
fullWidth
type="tel"
component={TextField}
/>
<ErrorMessage name={`Client.Phone.${index}.PhoneNumber`} /><br />
</Grid>
<Grid item xs={12} sm={3}>
<SectionField
title={title}
name={binding + `.Phone[${index}].PhoneType`}
required
defaultValue={{ label: "", value: "" }}
label="Phone Type"
suggestions={phoneTypes}
component={MuiReactSelect}
/>
</Grid>
<IconButton onClick={() => {
setPhones(currentPhone =>
currentPhone.filter(x => x.id !== p.id))
}}>
<RemoveCircleIcon fontSize="large" />
</IconButton>
</Fragment>
))}
</Fragment>
)
};export default Phone;
Formik values:
======================================================
"Phone": {
"0": {
"PhoneNumber": "8578882942",
"PhoneType": "Home"
},
"PhoneNumber": "8578882942",
"PhoneType": "Home"
},
I got into same sort of inconvenience when i wanted to delete that element from Ui but its values in formik stays there.
What i did was use formik's setFieldValue: (field: string, value: any, shouldValidate?: boolean) => void
So lets say you are using a button to remove that element from UI so i added an extra something to it like this to its onClick property :
//formik.setFieldValue({name of the element that you want to delete})
onClick = {()=>{
//whatever work you need to do for removing it from ui
//then
//formik.setFieldValue({name of the element that you want to delete})
formik.setFieldValue(index)
// here index was the name of variable that i used for that element
}}
Then in the formik's useFormik() hook i did something like this:
const formik = useFormik({
initialValues: {
//your initial values
},
onSubmit: (values) => {
// your onSubmit
},
setFieldValue: (field) => {
delete values.field;
},
});
Sorry i know that this answer is late but i hope it would help someone

Resources