My main objective is to use MUI time picker with yup validation and react-hook-form but the problem I'm facing is that when I choose time from time picker the value is not updated in the text field as shown below.
I have used type 'TIME' for my database so I need the input to be formatted. However, the working one (End Time) returns time with date which is not accepted in the database. The difference is shown in the console log below.
day: "tuesday"
end_time: "Tue May 31 2022 05:27:00 GMT+0545 (Nepal Time)"
start_time: "05:29:00"
subject: "Account"
[[Prototype]]: Object
Here is my source code:
import React, { useState, useEffect } from 'react'
import { Button, Box, Card, CardContent, TextField, Typography, CardHeader, Grid, MenuItem } from '@mui/material';
import { useNavigate, useParams } from 'react-router-dom';
import { useForm, Controller } from 'react-hook-form';
import { yupResolver } from '@hookform/resolvers/yup';
import * as Yup from 'yup';
import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns';
import { TimePicker, LocalizationProvider } from '@mui/x-date-pickers';
import { format, parseISO } from 'date-fns';
import TimeTableService from '../../../services/timetable.service';
import SubjectService from '../../../services/subject.service';
const TimetableForm = () => {
const { id } = useParams();
const validationSchema = Yup.object().shape({
day: Yup.string().required("Day is required"),
start_time: Yup.string().required("Start time is required"),
end_time: Yup.string().required("End time is required"),
subject: Yup.string().required("Subject is required"),
});
const {
control,
handleSubmit,
setValue,
formState: { errors }
} = useForm({ resolver: yupResolver(validationSchema), mode: 'onChange' });
const initialTimeTableState = {
id: null,
day: '',
start_time: '',
end_time: '',
Subject: {},
}
const [currentTimeTable, setCurrentTimeTable] = useState(initialTimeTableState);
const [subjects, setSubjects] = useState([]);
const [editMode, setEditMode] = useState(false);
const [loading, setLoading] = useState(false);
const [message, setMessage] = useState("");
const navigate = useNavigate();
useEffect(() => {
SubjectService.getAllSubjects().then(response => {
setSubjects(response.data);
})
if (id) {
TimeTableService.getTimeTable(id).then(response => {
const timeTable = response.data;
const fields = ['day', 'start_time', 'end_time'];
fields.forEach(field => setValue(field, timeTable[field]));
setValue('subject', timeTable.Subject.name);
setCurrentTimeTable(timeTable);
setEditMode(true);
})
}
}, [id, setValue]);
const onError = (errors, e) => console.log(errors, e);
const onSubmit = (data) => {
const start_time = data.start_time;
// const start = format(start_time, "hh:mm a");
console.log(start_time, data);
// setMessage("");
// setLoading(true);
// if (editMode) {
// TimeTableService.updateTimeTable(id, data).then(() => {
// setLoading(false);
// navigate("/dashboard/timetable");
// }, (error) => {
// const resMessage = (error.response && error.response.data && error.response.data.message) || error.message || error.toString();
// setLoading(false);
// setMessage(resMessage);
// });
// } else {
// TimeTableService.createTimeTable(data).then(() => {
// setLoading(false);
// navigate("/dashboard/timetable");
// window.location.reload();
// }, (error) => {
// const resMessage = (error.response && error.response.data && error.response.data.message) || error.message || error.toString();
// setLoading(false);
// setMessage(resMessage);
// });
// }
}
const days = [
{
title: "Sunday",
value: "sunday"
},
{
title: "Monday",
value: "monday"
},
{
title: "Tuesday",
value: "tuesday"
},
{
title: "Wednesday",
value: "wednesday"
},
{
title: "Thursday",
value: "thursday"
},
{
title: "Friday",
value: "friday"
},
{
title: "Saturday",
value: "saturday"
}
];
return (
<Box sx={{ mt: 3 }}>
<Card>
<Box sx={{ minWidth: 1050 }}>
<CardHeader
title={id ? "Edit Time Table" : "Add Time Table"}
/>
<CardContent>
{message && (<Typography variant='body2' color='error' >{message}</Typography>)}
<Grid container spacing={2}>
<Grid item md={4} xs={6}>
<LocalizationProvider dateAdapter={AdapterDateFns}>
<Controller
control={control}
name="start_time"
defaultValue={currentTimeTable.start_time || ""}
render={({ field }) => (
<TimePicker
{...field}
inputFormat="HH:mm:ss"
mask='__:__:__'
label="Start Time"
onChange={(time) => {
const formattedTime = format(time, "HH:mm:ss");
field.onChange(formattedTime);
}}
renderInput={(params) => (
<TextField
{...params}
fullWidth
label="Start Time"
variant="outlined"
margin='dense'
color='dark'
size='small'
error={errors.start_time ? true : false}
/>
)}
/>
)}
/>
</LocalizationProvider>
<Typography variant="body2" color="error">
{errors.start_time?.message}
</Typography>
</Grid>
<Grid item md={4} xs={6}>
<LocalizationProvider dateAdapter={AdapterDateFns}>
<Controller
control={control}
name="end_time"
defaultValue={currentTimeTable.end_time || ""}
render={({ field }) => (
<TimePicker
{...field}
label="End Time"
// onChange={(time) => field.onChange(time)}
renderInput={(params) => (
<TextField
{...params}
fullWidth
label="End Time"
variant="outlined"
margin='dense'
color='dark'
size='small'
error={errors.end_time ? true : false}
/>
)}
/>
)}
/>
</LocalizationProvider>
<Typography variant="body2" color="error">
{errors.end_time?.message}
</Typography>
</Grid>
<Grid item md={4} xs={6}>
<Controller
control={control}
name='subject'
defaultValue={currentTimeTable.Subject.name || ""}
render={({ field }) => (
<>
<TextField
{...field}
select
fullWidth
label='Subject'
variant='outlined'
margin='dense'
color='dark'
size='small'
error={errors.subject ? true : false}
>
{subjects.map(subject => (
<MenuItem key={subject.id} value={subject.name}>{subject.name}</MenuItem>
))}
</TextField>
</>
)}
/>
<Typography variant="body2" color="error">
{errors.subject?.message}
</Typography>
</Grid>
<Grid item md={4} xs={6}>
<Controller
control={control}
name='day'
defaultValue={currentTimeTable.day || ""}
render={({ field }) => (
<>
<TextField
{...field}
select
fullWidth
label='Day'
variant='outlined'
margin='dense'
color='dark'
size='small'
error={errors.day ? true : false}
>
{days.map(day => (
<MenuItem key={day.title} value={day.value}>{day.title}</MenuItem>
))}
</TextField>
</>
)}
/>
<Typography variant="body2" color="error">
{errors.day?.message}
</Typography>
</Grid>
</Grid>
<Button
variant='outlined'
color={(loading) ? 'warning' : 'success'}
sx={{ my: 1.5 }}
disabled={(loading) ? true : false}
onClick={handleSubmit(onSubmit, onError)}>
{(loading) ? "Loading..." : "Submit"}
</Button>
</CardContent>
</Box>
</Card>
</Box>
)
}
export default TimetableForm
Is there any way to fix this? Thanks.
NOTE: TimetableForm
component is rendered by using <Outlet />
of react route.
EDIT: This is the codeSandbox link : https://codesandbox.io/s/gifted-roentgen-94bnpq
The problem is in this line of code :
onChange={(time) => {
const formattedTime = format(time, "HH:mm:ss");
field.onChange(formattedTime);
}}
That's beacause format(time, "HH:mm:ss")
returns a String
, but the time picker expects a Date
object.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.