I'm trying to set the 'role' and 'active' values on a form.
The first problem is that the original values of the selectors are not set, which are fetched in the ManageUserDialog Props, so when starting the component the selectors are shown empty.
The second problem is that selecting one of the selector options doesn't set its value.
I attach images of the component, the code and the error delivered by the console.
import {
Button,
Dialog,
DialogActions,
DialogContent,
DialogTitle,
useMediaQuery,
useTheme,
Grid,
TextField,
MenuItem
} from '@mui/material';
import { Formik } from "formik";
import * as yup from 'yup';
import * as UsersApi from '../network/UsersApi';
import { useGlobalState } from '../context/hookStateProvider';
interface ManageUserFormInterface {
role: number;
active : boolean;
}
const ManageUserSchema = yup.object().shape({
role: yup.number().required("Required"),
active: yup.boolean().required("Required"),
});
interface Props {
userId: string;
userName: string;
active: boolean;
role: number;
isDialogOpen: boolean;
handleCloseDialog: () => void;
}
const roleItems = [
{label: 'User', value: 0},
{label: 'Manager', value: 1},
{label: 'Admin', value: 2}
];
const activeItems = [
{label: 'Yes', value: true},
{label: 'No', value: false}
];
const ManageUserDialog = ({userId, userName, active, role, isDialogOpen, handleCloseDialog}: Props) => {
const theme = useTheme();
const fullScreen = useMediaQuery(theme.breakpoints.down('md'));
const state = useGlobalState();
const initialValues: ManageUserFormInterface = {
role: role,
active: active,
}
const handleOkDialog = async (values: ManageUserFormInterface) => {
state.setLoading(true);
const { role, active } = values;
try {
await UsersApi.manageUser({userId, role, active});
} catch (error) {
console.log(error);
} finally {
state.setLoading(false);
handleCloseDialog();
}
}
return (
<Dialog
fullScreen={fullScreen}
open={isDialogOpen}
onClose={handleCloseDialog}
aria-labelledby="responsive-dialog-title"
sx={{
"& .MuiDialog-container": {
"& .MuiPaper-root": {
minWidth: "300px",
},
},
}}
>
<DialogTitle id="responsive-dialog-title">
{`Manage ${userName}`}
</DialogTitle>
<DialogContent>
<Formik
onSubmit={handleOkDialog}
initialValues={initialValues}
validationSchema={ManageUserSchema}
>
{({ values, errors, touched, handleBlur, handleChange, handleSubmit}) => (
<form onSubmit={handleSubmit} id="ManageUserForm">
<Grid container spacing={2} sx={{ mt: 3 }}>
<Grid item xs={12}>
<TextField
fullWidth
variant="filled"
select
label="Role"
onBlur={handleBlur}
onChange={handleChange}
value={values.role}
id="role"
name="role"
error={!!touched.role && !!errors.role}
helperText={touched.role && errors.role}
defaultValue={role}
>
<MenuItem>
{roleItems.map((role, index) => (
<MenuItem key={index} value={role.value}>
{role.label}
</MenuItem>
))}
</MenuItem>
</TextField>
</Grid>
<Grid item xs={12}>
<TextField
fullWidth
variant="filled"
select
label="Active"
onBlur={handleBlur}
onChange={handleChange}
value={values.active}
id="active"
name="active"
error={!!touched.active && !!errors.active}
helperText={touched.active && errors.active}
defaultValue={active}
>
<MenuItem>
{activeItems.map((active, index) => (
// eslint-disable-next-line @typescript-eslint/no-explicit-any
<MenuItem key={index} value={active.value as any}>
{active.label}
</MenuItem>
))}
</MenuItem>
</TextField>
</Grid>
</Grid>
</form>
)}
</Formik>
</DialogContent>
<DialogActions>
<Button onClick={handleCloseDialog}>
Cancel
</Button>
<Button type='submit' form="ManageUserForm">
Confirm
</Button>
</DialogActions>
</Dialog>
)
}
export default ManageUserDialog;
I tried changing TextField for Select but it happens the same.
I solved it, the problem was that I used MenuItem inside MenuItem. I only left the one inside the map in each TextField.
import {
Button,
Dialog,
DialogActions,
DialogContent,
DialogTitle,
useMediaQuery,
useTheme,
Grid,
TextField,
MenuItem
} from '@mui/material';
import { Formik } from "formik";
import * as yup from 'yup';
import * as UsersApi from '../network/UsersApi';
import { useGlobalState } from '../context/hookStateProvider';
interface ManageUserFormInterface {
role: number;
active : boolean;
}
const ManageUserSchema = yup.object().shape({
role: yup.number().required("Required"),
active: yup.boolean().required("Required"),
});
interface Props {
userId: string;
userName: string;
active: boolean;
role: number;
isDialogOpen: boolean;
handleCloseDialog: () => void;
}
const roleItems = [
{label: 'User', value: 0},
{label: 'Manager', value: 1},
{label: 'Admin', value: 2}
];
const activeItems = [
{label: 'Yes', value: true},
{label: 'No', value: false}
];
const ManageUserDialog = ({userId, userName, active, role, isDialogOpen, handleCloseDialog}: Props) => {
const theme = useTheme();
const fullScreen = useMediaQuery(theme.breakpoints.down('md'));
const state = useGlobalState();
const initialValues: ManageUserFormInterface = {
role: role,
active: active,
}
const handleOkDialog = async (values: ManageUserFormInterface) => {
state.setLoading(true);
const { role, active } = values;
try {
await UsersApi.manageUser({userId, role, active});
} catch (error) {
console.log(error);
} finally {
state.setLoading(false);
handleCloseDialog();
}
}
return (
<Dialog
fullScreen={fullScreen}
open={isDialogOpen}
onClose={handleCloseDialog}
aria-labelledby="responsive-dialog-title"
sx={{
"& .MuiDialog-container": {
"& .MuiPaper-root": {
minWidth: "300px",
},
},
}}
>
<DialogTitle id="responsive-dialog-title">
{`Manage ${userName}`}
</DialogTitle>
<DialogContent>
<Formik
onSubmit={handleOkDialog}
initialValues={initialValues}
validationSchema={ManageUserSchema}
>
{({ values, errors, touched, handleBlur, handleChange, handleSubmit}) => (
<form onSubmit={handleSubmit} id="ManageUserForm">
<Grid container spacing={2} sx={{ mt: 3 }}>
<Grid item xs={12}>
<TextField
fullWidth
variant="filled"
select
label="Role"
onBlur={handleBlur}
onChange={handleChange}
value={values.role}
id="role"
name="role"
error={!!touched.role && !!errors.role}
helperText={touched.role && errors.role}
>
{/* Here Changes */}
{roleItems.map((r, index) => (
<MenuItem key={index} value={r.value}>
{r.label}
</MenuItem>
))}
</TextField>
</Grid>
<Grid item xs={12}>
<TextField
fullWidth
variant="filled"
select
label="Active"
onBlur={handleBlur}
onChange={handleChange}
value={values.active}
id="active"
name="active"
error={!!touched.active && !!errors.active}
helperText={touched.active && errors.active}
>
{/* Here Changes */}
{activeItems.map((active, index) => (
// eslint-disable-next-line @typescript-eslint/no-explicit-any
<MenuItem key={index} value={active.value as any}>
{active.label}
</MenuItem>
))}
</TextField>
</Grid>
</Grid>
</form>
)}
</Formik>
</DialogContent>
<DialogActions>
<Button onClick={handleCloseDialog}>
Cancel
</Button>
<Button type='submit' form="ManageUserForm">
Confirm
</Button>
</DialogActions>
</Dialog>
)
}
export default ManageUserDialog;