简体   繁体   中英

MUI Time picker doesn't show formatted time value in input field

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM