I have a form with a datePicker input from material-ui
When I pick a date and submit my form, if I console.log my data I will receive 'Tue Jan 10 2023 10:31:48 GMT+0100 (Central European Standard Time)' i want to received '01/11/2023'
I would like to format the data received.
Here my DatePicker :
const [deadLine, setDeadLine] = useState(new Date());
<Controller
name="deadLine"
defaultValue={deadLine}
control={control}
render={({ field: { onChange, ...restField } }) => (
<LocalizationProvider dateAdapter={AdapterDateFns}>
<DatePicker
label="Request Date"
onChange={(event) => {
console.log(event);
onChange(event);
setDeadLine(event);
}}
renderInput={(params) => <TextField {...params} />}
{...restField}
/>
</LocalizationProvider>
)}
/>
I have already tried :
To Use "format="dd-MM-yyyy"" from material-ui, but it only change the
visual not the data received.
To use moment with
setDeadLine(moment(event.target.value).format('MM/DD/YYYY'));,
still received the initial value.
To know : I am using react-hook-form
First of all to use moment you should wrap you DatePicker with moment Adapter:
<LocalizationProvider dateAdapter={AdapterMoment}> more also, onChange return the value you shouldn't access it with event.target.value, but you have directly the value with moment(value).format('DD/MM/YYYY') and of course don't forget to import Adapter Moment - import { AdapterMoment } from '#mui/x-date-pickers/AdapterMoment';
It should look like that:
<LocalizationProvider dateAdapter={AdapterMoment}>
<DatePicker
label="Request Date"
onChange={(value) => {
setDeadLine(moment(value).format('DD/MM/YYYY'));
}}
renderInput={(params) => <TextField {...params} />}
{...restField}
/>
</LocalizationProvider>
Related
I have a bit of a custom TimePicker provided from Material UI. I add an ability for the user to select only whole hours, such as 15:00, 16:00 etc. by clicking on a clock icon
What I want to achieve is to add same for manual input of the text field. For now user can manually add any valid time, for example 14:34, which is incorrect for my case
Can anyone help me?
Here is my TimePicker:
<LocalizationProvider dateAdapter={AdapterDateFns} locale={locale}>
<TimePicker
ampm={false}
openTo="hours"
views={['hours']}
inputFormat="HH:mm"
mask="__:__"
value={dayStartValue}
InputAdornmentProps={{
position: 'start',
}}
components={{
OpenPickerIcon: ClockFilledIcon,
}}
onChange={(newValue) => {
setDayStartValue(newValue)
}}
renderInput={(params) =>
<TextField
{...params}
helperText="Input start of Day time"
/>
}
/>
</LocalizationProvider>
You can control and validate the user's input when he clicks away from the time picker by using onBlur inside InputProps.
import * as React from "react";
import TextField from "#mui/material/TextField";
import { AdapterDateFns } from "#mui/x-date-pickers/AdapterDateFns";
import { LocalizationProvider } from "#mui/x-date-pickers/LocalizationProvider";
import { TimePicker } from "#mui/x-date-pickers/TimePicker";
export default function BasicTimePicker() {
const [dayStartValue, setDayStartValue] = React.useState<Date | null>(null);
return (
<LocalizationProvider
dateAdapter={AdapterDateFns}
locale={locale}
>
<TimePicker
ampm={false}
openTo="hours"
views={["hours"]}
inputFormat="HH:mm"
mask="__:__"
value={dayStartValue}
InputAdornmentProps={{
position: "start"
}}
components={{
OpenPickerIcon: ClockFilledIcon,
}}
onChange={(newValue: Date, keyboardInputValue?: string) => {
setDayStartValue(newValue);
}}
renderInput={(params) => (
<TextField {...params} helperText="Input start of Day time" />
)}
InputProps={{
onBlur: (
e: React.FocusEvent<HTMLInputElement | HTMLTextAreaElement, Element>
) => {
const newDate = new Date(dayStartValue);
newDate.setMinutes(0);
if (e.target.value && e.target.value.length === 5) {
setDayStartValue(newDate);
}
}
}}
/>
</LocalizationProvider>
);
}
For the validation we check the user input and if it's a valid Date (5 characters length), we create a new Date with that and set the minutes to 0.
Code Sandbox example
You can change your input format and the mask to only accept whole hours like so:
<LocalizationProvider dateAdapter={AdapterDayjs}>
<TimePicker
ampm={false}
openTo="hours"
views={['hours']}
inputFormat="HH:00"
mask="__:00"
value={value}
InputAdornmentProps={{
position: 'start',
}}
onChange={(newValue) => {
setValue(newValue)
}}
renderInput={(params) =>
<TextField
{...params}
helperText="Input start of Day time"
/>
}
/>
</LocalizationProvider>
sandbox
I'm using DatePicker in side a react hook form.
I'm able to get my form to display the Date I pick but it's not in the format I'm expecting.
The text box the is correct August 19, but when I try to get it to display using
it comes back at as this format 2022-09-19T23:51:47.000Z
I'm not sure what I'm missing as i'm pretty stump at the moment on what needs for it to display correctly.
<LocalizationProvider dateAdapter={AdapterDateFns}>
<Controller
name="Date"
control={control}
defaultValue=""
rules={{
required: { value: true, message: "Date is required" },
}}
render={({ field }) => (
<DatePicker
openTo="month"
views={["month", "day"]}
label="month and date"
value={field.value}
onChange={(e, data) =>
field.onChange(data);
}
inputFormat="MMMM dd"
renderInput={(params) => (
<TextField {...params} helperText={null} />
)}
{...field}
/>
)}
/>
</LocalizationProvider>
If you're using date-fns you can do this with the ISOString:
format(new Date('2022-09-19T23:51:47.000Z'), 'MMMM DD', { locale: 'US' });
It would return:
September 19
In my MUI form I'm using DatePicker to select dates for departure and return of users. But when I used .toLocaleDateString() it set my dates in mm-dd-yyyy format. But I wanted to set them as dd-mm-yyyy format. For that I've passed 'en-GB' as parameter in .toLocaleDateString(). But in the DatePicker TextField it shows a red border Like this and the pre-defined date (from the state) are also gone. Without the parameter it shows This which is the mm-dd-yyyy format. From the similar previous questions I even tried it through moment package and set the dt variable as moment(new Date()).format("DD/MM/YYYY") but it is still showing red border around the text field. I know this question was asked a lot of times before and I went through all of them and got no solution.
Date picker
const dt = new Date().toLocaleDateString();
console.log(dt);
const [formData, setFormData] = useState({
from: "",
to: "",
depart: dt,
return: dt,
noOfPassenger: 1,
tripType: "Return",
});
{/* App component */}
<div className="dates">
<LocalizationProvider dateAdapter={AdapterDateFns}>
<DatePicker
label="Departure Date"
disablePast
onChange={(e) =>
setFormData({
...formData,
depart: e.toLocaleDateString(),
})
}
value={formData.depart}
renderInput={(params) => <TextField {...params} required />}
/>
</LocalizationProvider>
</div>
In my case I used a DateRangePicker, but it's the same across all pickers.
Just set the inputFormat like here:
<DateRangePicker
startText={t`From`}
endText={t`To`}
value={dateValue}
inputFormat="dd.MM.yyyy"
onChange={(newValue) => {
setDateValue(newValue);
console.log(newValue);
}}
renderInput={(startProps, endProps) => (
<React.Fragment>
<TextField {...startProps} />
<TextField {...endProps} />
</React.Fragment>
)}
/>
Emanuel Avram has already given a good answer. I will just add.
The value (date) of the component must have the same format defined internally, so it's no use using "toLocaleString()" without changing the internal format. Use the "inputFormat" property.
// "dd" = "Su", "Mo", ..., "Sa"
// "DD" = "01", "02", ..., "31"
inputFormat="dd/MM/YYYY" // Tu/09/2022
inputFormat="DD/MM/YYYY" // 09/13/2022
<DatePicker
label="Departure Date"
inputFormat="DD-MM-YYYY" // 13-09-2022
onChange={(e) =>
setFormData({
...formData,
depart: e.toLocaleDateString(),
})
}
value={formData.depart}
renderInput={(params) => <TextField {...params} required />}
/>
I'm using MUI datepicker along with React hook form, I'm using #mui/lab/AdapterMoment as date adaptor.
In local environment, datepicker's onChange is working fine. But when it is built and deployed in production, onChange is not working so if I click on a date nothing is happening. I tested react hook and it seems to be working fine. Can anyone help me figure out this issue?
<LocalizationProvider dateAdapter={DateAdapter}>
<Controller
name="reminderFromDate"
control={control}
rules={{
required: true,
}}
render={({ field: { onChange, value } }) => (
<div className="reminder_form_err_container remeberFieldInput">
<DatePicker
className="login_input remeberFieldInput ip-field w-100 "
label="Date"
mask="___ __ ___, ____"
inputFormat={"ddd D MMM, YYYY"}
value={value}
disablePast
readOnly
onChange={(e) => onChange(e)}
renderInput={(params) => (
<TextField
{...params}
onClick={(e) => setStartDate(true)}
/>
)}
open={isStartDate}
onClose={() => setStartDate(false)}
/>
{errors.reminderFromDate && (
<span className="reminder_text-danger" role="alert">
{"This field is required"}
</span>
)}
</div>
)}
/>
</LocalizationProvider>
I got the following datepickers.
For the Start Date:
<Controller
as={
<DatePicker
selected={travelRoute?.dateStart || new Date()}
selectsStart
startDate={travelRoute?.dateStart}
endDate={travelRoute?.dateEnd}
inline
/>
}
control={control}
rules={{ required: true }}
valueName="selected"
onChange={date => handleStartDateOnChange(date)}
name="dateStart"
placeholderText="Select date"
defaultValue={null}
/>
For the End Date:
<Controller
as={
<DatePicker
name="dateEnd"
selected={travelRoute?.dateEnd || new Date()}
onChange={date => handleEndDateOnChange(date)}
selectsEnd
startDate={travelRoute?.dateStart}
endDate={travelRoute?.dateEnd}
minDate={travelRoute?.dateStart}
inline
/>
}
control={control}
rules={{ required: true }}
valueName="selected"
onChange={date => handleEndDateOnChange(date)}
name="dateEnd"
placeholderText="Select date"
defaultValue={null}
/>
Do I need to add the datepicker props to the datepicker component or to the Controller Component?
The start Datepicker doesn't select the date and the end Datepicker doesn't change the startdate and isn't displaying the range.
I'm saving the data into the travelRoute state with setTravelRoute which is happening in the handleOnChange functions.
EDIT:
Added onChange handler:
const handleStartDateOnChange = date => {
setTravelRoute(prevState => ({
...prevState,
dateStart: date
}))
};
const handleEndDateOnChange = date => {
setTravelRoute(prevState => ({
...prevState,
dateEnd: date
}))
};
Ciao, you are using the wrong approach to customize your onChange event in DatePicker. And onChange event on Controller can't work neihter. Because in this case, you don't have to use as= syntax, but render= syntax like:
<Controller
render={({ onChange }) => (
<DatePicker
...
onChange={date => handleStartDateOnChange(date)}
/>
)}
...
/>
So your code becomes:
Start Date
<Controller
render={({ onChange }) => (
<DatePicker
selected={travelRoute?.dateStart || new Date()}
selectsStart
startDate={travelRoute?.dateStart}
endDate={travelRoute?.dateEnd}
inline
onChange={date => handleStartDateOnChange(date)}
/>
)}
control={control}
rules={{ required: true }}
valueName="selected"
name="dateStart"
placeholderText="Select date"
defaultValue={null}
/>
End Date
<Controller
render={({ onChange }) => (
<DatePicker
name="dateEnd"
selected={travelRoute?.dateEnd || new Date()}
onChange={date => handleEndDateOnChange(date)}
selectsEnd
startDate={travelRoute?.dateStart}
endDate={travelRoute?.dateEnd}
minDate={travelRoute?.dateStart}
inline
/>
)}
control={control}
rules={{ required: true }}
valueName="selected"
name="dateEnd"
placeholderText="Select date"
defaultValue={null}
/>
Here a working example.
Note: I don't know why DatePicker in codesandbox looks so ugly. Could be the Controller because in this other codesandbox looks good.
I have had a different approach to the solution of this issue and wanted to share it.
I answered some related issue in the following post: https://stackoverflow.com/a/72585781/19320134
Anyway, one way to make the code more reusable is to put these controllers in separate files, so that only the function name is imported when calling them.
export const DateRange = ({ name, control, label }) => {
const [dateRange, setDateRange] = useState([null, null]);
const [startDate, endDate] = dateRange;
return (
<Controller
//is a prop that we get back from the useForm Hook and pass into the input.
control={control}
//is how React Hook Form tracks the value of an input internally.
name={name}
//render is the most important prop; we pass a render function here.
render={({
//The function has three keys: field , fieldState, and formState.
field, // The field object exports two things (among others): value and onChange
}) => (
<>
<DatePicker
selectsRange={true}
startDate={startDate}
endDate={endDate}
onChange={(e) => {
setDateRange(e);
field.onChange(e);
}}
isClearable={true}
className="form-control"
/>
</>
)}
rules={{
required: `The ${label} field is required`,
}}
/>
And you can call it in the necesary file like this
import { useForm, Controller, FormProvider } from "react-hook-form";
import {DateRange} from "./your file !"
const defaultValues = {
dateRange: [],
};
export default function ComponentUsingDateRange() {
const methods = useForm({
defaultValues,
mode: "onChange",
});
const { register, handleSubmit, control, setValue } = methods;
return(
<>
<FormProvider {...methods}>
<DateRange
control={control}
name="dateRange"
label="Range of dates"
/>
</FormProvider>
</>
);
}