英文:
Problems setting the values of a form using Material UI, Formik and Typescript
问题
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) => (
<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'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.
答案1
得分: 0
我解决了问题,问题是我在MenuItem内部使用了MenuItem。我只在每个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}
>
{/* 这里有变化 */}
{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}
>
{/* 这里有变化 */}
{activeItems.map((active, index) => (
<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;
英文:
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;
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论