Clear react-datepicker on form reset in react-final-form - reactjs

I'm using react-final-form and react-datepicker. I also have a select for year. Start and end dates should be set to January 1 and December 31 of the default year. When a new year is selected I would like to reset the form, clear selected dates and input values of both datepickers and set them to January 1 and December 31 of the selected year respectively.
Here is the link to my codesandbox https://codesandbox.io/s/react-datepicker-clear-cxlxh.
So far, I have a custom component for react-datepicker which works with react-final-form. Start and end dates are set to January 1 and December 31 of the default year.
DatePicker component:
const DatePickerWrapper = props => {
const { input, label, minDate, maxDate } = props;
const [startDate, setStartDate] = useState(input.value);
return (
<div>
<label>{label}</label>
<DatePicker
selected={startDate}
minDate={minDate}
maxDate={maxDate}
onChange={value => {
setStartDate(value);
props.input.onChange(value);
}}
onBlur={props.input.onBlur}
onFocus={props.input.onFocus}
value={props.input.value}
/>
</div>
);
};
And Field where it is used:
<Field
name="startDate"
initialValue={isoDate(minDate(values.year.value))}
component={DatePickerWrapper}
minDate={minDate(values.year.value)}
maxDate={
values.endDate ? values.endDate : maxDate(values.year.value)
}
/>
Here is my component for resetting the form:
<Field name="year" subscription={{}}>
{({ input: { onChange } }) => (
<OnChange name="year">
{value => {
form.reset({
...initialValues,
year: value
});
}}
</OnChange>
)}
</Field>
So my questions are:
How can I clear react-datepicker and its input value on form reset? There is a clear() function, but I couldn't make it to work.
How can I then set the dates to January 1 and December 31 of the selected year? I've added initialValue for each field and the values of the form are updated. But the inputs' values stay the same.

You have few issues in the form.
You are giving initial values to you dates twice. Once at the top and then again as the props. This is causing the render to go into infinite loop. Have moved all the form initialization to top in object
const initialValues = {
year: { value: "2019", label: "2019" },
startDate: isoDate(minDate("2019")),
endDate: isoDate(maxDate("2019")),
amount: ""
};
When you are doing form.reset for the year, at that place you can reset the value for the start date and end date
form.reset({
...initialValues,
year: value,
startDate: isoDate(minDate(value.value)),
endDate: isoDate(maxDate(value.value))
});
From the given code, I didn't see any requirement for usestate in datepicker.jsx as it seemed to be getting handled by the form. And so have removed it.
I have updated the code in the Sandbox.
Have a look at it and let me know if any thing is missed or you have any doubts.

The value is stored in this.component_name.current.state, so use an assignment operator and assign an empty string to it. do this operation in a callback of a state change operation (either a setState or a useState). Should work. worked for me.
this.startdate.current.state.value = "";
this.startdate.current.state.inputValue = "";

Related

How to externally set calendar value in primereact?

I added a couple buttons to the calendar footer, just to set the value to a specific date. The date is declared with usestate, and when I click the button, the value of the date variable is set appropriately, I also see the calendar UI changing the highlighted day, although I need to use setState() on the calendar to move the UI to the new month/year if that's required. The overall structure is like this:
const [date, setDate] = useState<Date | Date[]>(new Date());
const presetDate = new Date(2021,4,2);
const calendar = useRef<Calendar>(null);
const setCalendarValue = (targetDate: Date) => {
setDate(targetDate);
let calendarState = calendar.current?.state;
calendar.current?.setState({
focused: calendarState?.focused ?? false,
overlayVisible: calendarState?.overlayVisible ?? false,
viewDate: targetDate
});
}
const calendarFooter = () => {
return (
<>
<Button label="Preset date" onClick={() => setCalendarValue(presetDate) }
</>
)
}
retun(
<>
<Calendar
ref={calendar}
field="date"
label="Date"
id="date"
minDate={new Date(2000,0,1)}
value={date?? undefined}
onChange={(e) => setDate(e.value || new Date())}
/>
</>
);
Everything works except that the textbox with the date does not show the newly assigned date until the calendar is closed, then reopened, and the button clicked a second time. Specifically in this order.
So far as I understand, I need to cause the input event on the calendar, but I can't seem to find out how it's done, and the event dispatcher is not exposed, even though I do see it in the source of the calendar component itself.

Getting "A component is changing an uncontrolled input to be controlled (...)" when using KeyboardDatePicker

A reproducible example can be found in this link.
I'm starting with React and Hooks. Currently, I'm trying to build a configuration form to generate some reports. The first sub-component of my entire form that I'm building is a Filter component with only two dates (start and end dates).
In the outer component called Configuration I have the form state and the start and end dates are passed by props to the Filter component as well the onPeriodChange callback:
export const Configuration: React.FC = () => {
const [periodState, setPeriodState] = useState<Period>({
startDate: '',
endDate: '',
});
const handlePeriodChange = useCallback(
(field: keyof Period, value: string) =>
setPeriodState({ ...periodState, [field]: value }),
[periodState],
);
return (
<MuiPickersUtilsProvider utils={DateFnsUtils}>
<form name="configuration">
<Filters period={periodState} onPeriodChange={handlePeriodChange} />
</form>
</MuiPickersUtilsProvider>
);
};
Then, the props are passed to KeyboardDatePicker components in the Filter components:
export const Filters: React.FC<FilterProps> = (filterProps: FilterProps) => {
const { period, onPeriodChange } = filterProps;
return (
(...)
<KeyboardDatePicker
disableToolbar
fullWidth
variant="inline"
format="dd/MM/yyyy"
id="start-date"
label="Data de descarga inicial:"
value={period.startDate}
onChange={(date) => {
onPeriodChange(
'startDate',
date instanceof Date && !Number.isNaN(date)
? date.toISOString()
: '',
);
}}
required
KeyboardButtonProps={{
'aria-label': 'change date',
}}
/>
(...)
);
};
In the first render, the components are displayed as invalid:
And when I change the value of the first component I'm getting a console warning saying (you can reproduce this behavior in the sandbox):
Warning: A component is changing an uncontrolled input to be controlled. This is likely caused by the value changing from undefined to a defined value, which should not happen. Decide between using a controlled or uncontrolled input element for the lifetime of the component.
I don't know why I'm getting this error, since the initial values of the start and end date are an empty string (and not undefined). Can you point me where is my mistake? Thanks!
This is because the period value changes from an empty string to a Date, in your initial value, you should also pass a Date.
Warning: A component is changing an uncontrolled input to be controlled. This is likely caused by the value changing from undefined to a defined value, which should not happen. Decide between using a controlled or uncontrolled input element for the lifetime of the component.
Interface update
export interface Period {
startDate: Date;
endDate: Date;
}
Initial state update
const [periodState, setPeriodState] = useState<Period>({
startDate: new Date(),
endDate: new Date()
});

How to create a simple formik field for entering date and time?

I am trying to create a very simple formik field for entering date and time. The requirements are:
The field's value should be a JavaScript Date.
The field should allow entering free-form text in an input field and convert it to a Date on blur events.
The field should display an error if the entered string cannot be converted to a valid date.
If the form is reset, the field should show the initial value of the date.
While I was able to satisfy requirements 1 & 2 quite easily, I am having trouble with requirements 3 & 4. I think part of the problem is that I am storing the raw text of the input field in internal state. However, I can't think of another way. Is there a better pattern?
Here's my CodeSandbox. Please see the sections marked with "Issue 1" & "Issue 2"
Try this solution:
Use Field component from Formik to bind your custom component
<Field name="date" timezone={DefaultTz} component={DateTimeField} />
Use form property from Field to display errors
{form.errors.date ? (
<div className="text-danger">{form.errors.date}</div>
) : null}
Use spread operator to bind formik fields and your custom blur which converts the date
<input
className="form-control"
placeholder={format}
{...{ ...field, onBlur }}
/>
Altogether it looks like this
import React from "react";
import { DateUtils } from "#react-force/date-utils";
export interface DateTimeFieldProps extends React.InputHTMLAttributes<Date> {
field: any;
form: any;
timezone: string;
format?: string;
}
export const DateTimeField = ({
field,
form,
timezone,
format = "YYYY-MM-DD hh:mm A",
}: DateTimeFieldProps) => {
const onBlur = () => {
try {
form.setValues({
date: DateUtils.createDate(field.value, format, timezone),
});
} catch (error) {
console.log(error);
}
};
return (
<React.Fragment>
<input
className="form-control"
placeholder={format}
{...{ ...field, onBlur }}
/>
{form.errors.date ? (
<div className="text-danger">{form.errors.date}</div>
) : null}
</React.Fragment>
);
};
The working version is here

React datepicker disable dates after two weeks

I am using react-datepicker module in my website. I want to disable the dates after 2 weeks. for example, today date is : 20-02-2019, so i want to disable dates after 5 march 2019.
How can i do that?
You can give a date that is 13 days into the future to the maxDate prop.
Example (CodeSandbox)
class App extends React.Component {
state = {
startDate: new Date()
};
handleChange = date => {
this.setState({
startDate: date
});
};
render() {
const twoWeeksFromNow = new Date();
twoWeeksFromNow.setDate(twoWeeksFromNow.getDate() + 13);
return (
<DatePicker
selected={this.state.startDate}
onChange={this.handleChange}
maxDate={twoWeeksFromNow}
/>
);
}
}
ReactDOM.render(<App />, document.getElementById("root"));
You can add maxDate attribute to your datepicker code.
maxDate={addDays(new Date(), 13)}
The react-datepicker component you are using, already has includeDates parameter.
() => {
const [startDate, setStartDate] = useState(null);
return (
<DatePicker
selected={startDate}
onChange={date => setStartDate(date)}
includeDates={[new Date(), addDays(new Date(), 1)]}
placeholderText="This only includes today and tomorrow"
/>
);
};
This above code is for showing only today and tomorrow. If you want to show dates for two weeks, simply add the list of days in array (line 7).
Link for that particular section https://reactdatepicker.com/#example-include-dates

React Datepicker( can't get value of input)

I am new in react. I need use react-datepicker
I want to get value of input, when I change date.
If i click on 20th October 2017, i want put 20th October 2017 in my variable.
But the main problem that I should work with component, not with input.
Before I just took value from state. Like this.state.value. But right now it is object(Moment) in state. And this object doesn't have value field.
There is my code:
export default class DatePicker extends Component {
constructor (props) {
super(props);
// this.props.date should looks like "29 November 2017 00:00"
// second argument for moment() it is format of date, because RFC 2822 date time format
this.state = {
date: moment(this.props.value, 'LLL')
};
}
handleChange = (date) => {
// const valueOfInput = this.state.date <--- I want string with date here
console.log('this.state.date',this.state.date);
this.setState({date: date});
};
render() {
return <Form.Field>
<Label>
<Picker
selected={this.state.date}
onChange={this.handleChange}
dateFormat="LLL"
locale={this.props.language}
/>
</Label>
</Form.Field>
Just use this:
handleChange = date => {
const valueOfInput = date.format();
///...
};
Because this datepicker returns a moment.js object!
For more information, look into the moment.js docs here.
Try this
<DatePicker
onChange={(value, e) => this.handleChange(value, e)}
selected={this.state.inputValue} otherProps={here}
/>
// you can access the value field in handleChange by e.target.value
handleChange(value, e) {
console.log(value); // this will be a moment date object
console.log(e.target.value); // this will be a string value in datepicker input field
}
This solved for me by using the following:
handleDateChange = date => {
let selectedDateFromCalender = date.toUTCString();
this.setState({
actualStartDate: selectedDateFromCalender,
});}
<DatePicker
selected={this.state.startDate}
onChange={this.handleDateChange}/>
You can use the following methods as well, choose according to your requirement:
toISOString: "2020-10-05T09:10:38.000Z"
toJSON: "2020-10-06T09:09:16.000Z"
toUTCString: "Thu, 08 Oct 2020 09:11:24 GMT"
If you want to get the new value (once the user clicks on a new date from DatePicker) pass the event to the method.
class MyComponent extends React.Component {
constructor(props) {
this.state = {inputValue: moment(),} // this will set the initial date to "today",
// you could also put another prop.state value there
this.handleChange = this.handleChange.bind(this);
}
}
handleChange(value) {
console.log(value); // this will be a moment date object
// now you can put this value into state
this.setState({inputValue: value});
}
render(){
...
<DatePicker
onChange={(event) => this.handleChange(event)}
selected={this.state.inputValue} otherProps={here} />
...
}
};
The new version of react-datepicker library stopped using a moment.js object, so here is my solution if you want to get a formatted string representation of the date.
First import
import format from "date-fns/format";
Then
<DatePicker
onChange={(value)=>this.handleChange(format(value, "yyyy/MM/dd", {
awareOfUnicodeTokens: true }))}
dateFormat="yyyy/MM/dd"
selected={this.state.inputValue} otherProps={here} />
...
You can use the getTime() helper function on your date object to get the millisecond timestamp for that specific date, which is a JavaScript number data type. Useful for saving data in the backend of your application. For example Flask Peewee ORM requires a timestamp to be saved for the DateTimeField.
const [startDate, setStartDate] = useState(new Date())
<DatePicker
onSelect( date => {
setStartDate(getTime(date))
}
/>
source: https://date-fns.org/v2.0.0-alpha.7/docs/getTime
Combine it with an effect to set the default state value to a timestamp on page load:
useEffect(() => {
setStartDate(getTime(startDate))
}, [])
Otherwise for your UI, you can use the format() helper function to get the string value of the given object, with any given format:
<h1>{format(startDate, "MMMM d, yyyy h:mm aa")}</h1>
source: https://date-fns.org/v2.0.0-alpha.7/docs/format
I have same problem, and I solved it by using the below solution. Please try it:
<p>{this.state.date.toLocaleDateString()}</p>
<input id="tdate" type="date" name="todate" onchange="getToDate(event);">
function getToDate(e){
const tdate = e.target.value;
//alert(tdate);
//console.log(tdate);
//return tdate;
};
here i am trying to access "tdate" variable outside the function.

Resources