React-datepicker with custom input with manual typing - reactjs

I am trying to create react-datepicker component with custom styled input:
<DatePicker
selected={startDate}
customInput={<CustomInput inputRef={inputRef} />}
onChangeRaw={(e) => handleChangeRaw(e)}
onChange={(date: Date | null) => {
setStartDate(date);
}}
/>
const CustomInput = forwardRef((props: any, ref) => {
return <Input {...props} ref={ref} />;
});
I wanted to introduce validation (just simple validation that whatever user inputs will be formatted to the date so user cannot just type whatever he wants).
I created a function that would be formatting the input using onChangeRaw attribute in react-datepicker:
const handleChangeRaw = (date) => {
date.currentTarget.value = format(startDate, "dd/MM/yyyy");
};
However after using this I cannot type anymore. Anyone has idea how to use manual typing with custom input in react-datepicker with simple validation function?
Here is recreated issue in the sandbox:
https://codesandbox.io/s/react-datepicker-custominput-sample-forked-elx310?file=/src/App.tsx

selected={startDate}
Here react-datepicker expects a Date object.
However, when you trigger handleChangeRaw, you get an change event, with some value (date.currentTarget.value), but thats not in the Date notation that datepicker expects.
So my take on this would be;
onChangeRaw, convert the input value to a new Date.
If the date isn't valid, just ignore the change
Otherwise, create a new Date, and use setStartDate to change to that new date
const handleChangeRaw = (date) => {
const newRaw = new Date(date.currentTarget.value);
if (newRaw instanceof Date && !isNaN(newRaw)) {
setStartDate(newRaw);
}
};
Try it online

If I understand your issue correctly, you can add the following type to fix the typing.
const handleChangeRaw = (date: React.FocusEvent<HTMLInputElement>) => {
if (!startDate){
return
}
date.currentTarget.value = format(startDate, "dd/MM/yyyy");
};
date should have the type React.FocusEvent<HTMLInputElement>. Since startDate can be null, we have to check before using it. In this case I just return from the function. But you could also assign a default value here or something else.

Related

How do I properly store an array of dates from React Multi Date Picker

I'm creating a form that needs the user to select multiple days, not in a range. I'm trying to implement the multi-date-picker but anything I've tried has returned undefined.
I very new so assume I'm missing something basic here, any help on how this should be set up is appreciated.
const {
date
} = useAppContext()
const[values,setValue] = React.useState([]);
const handleDates = (value) =>{
const name = 'date'
setValue({...values, value})
handleChange({ name, values })
}
<DatePicker
multiple
value={values}
name= "date"
onChange={handleDates}
minDate="2023/02/16"
maxDate="2023/02/26"
/>
Here you define value as an array []:
const[values,setValue] = React.useState([]);
However, you change it into an object here:
setValue({...values, value}); // destructured object
This should be:
setValue([...values, value]); //<--- destructured array

Proper way to change calendar date clear icon in DatePicker for AntD

I want to change the clear icon of a date picker from the ant design framework.
Is it possible ?
Reason - I want to reset the date to today when it clicks. So close-icon is not appropriate.
Since antd uses rc-picker to create DatePicker component, you can use clearIcon attribute to customize clear icon, but since you need to reset datePicker's value to today with click on clear, you need to do a bit more to handle this requirement, here is an example:
function PickerWithCustomClear() {
const [date, setDate] = React.useState(null);
const [shoudlReset, setShouldReset] = React.useState(false);
const onChange = (date) => {
setDate(date);
if (!date && shoudlReset) {
setDate(moment());
setShouldReset(false);
}
};
return (
<DatePicker
onChange={onChange}
allowClear={true}
value={date}
clearIcon={
// you can use every element here
<SyncOutlined onMouseDown={(e) => setShouldReset(true)} />
}
/>
);
}
I've implemented an example you can find it Here.

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()
});

Access data from an array of dates

My application can get data from user. For this i have different inputs. One of my inputs is date Picker.
<Form.Item name="Picker" label="date">
<RangePicker
showTime={{ format: "HH:mm" }}
format="YYYY-MM-DD HH:mm"
onChange={onChange2}
onOk={onOk}
/>
</Form.Item>
The issue appear when i try to access data after clicking on submit button. In console i have all data from each input, but from RangePicker, the data is not structured, and i get:
Picker: Array[2]
0: Moment
1: Moment
The problem is that i can access this array, and display on fron end. How to do this?
link to my app: https://codesandbox.io/s/form-methods-ant-design-demo-kbwgk
Try this
import moment from 'moment'
const onFinish = values => {
const startDate = moment(values.Picker[0]).format("YYYY-MM-DD HH:mm");
const endDate = moment(values.Picker[1]).format("YYYY-MM-DD HH:mm");
console.log(startDate, endDate)
};
I got it,
on your rangepicker use
onFinish instead of onOk
<RangePicker
showTime={{ format: "HH:mm" }}
format="YYYY-MM-DD HH:mm"
onChange={onChange2}
onFinish={onFinish}
/>
working as specified
you press Ok twice , so the first onOk still doesnt include the second part of the range
sorry for not giving professional answer
Since you are getting it as an array of moment objects,try using moment js for formatting the moment js according to your needs
https://codesandbox.io/s/form-methods-ant-design-demo-sy4uq
function onOk(value) {
const start = moment(value[0]).format("YYYY-MM-DD HH:mm:ss");
const end = moment(value[1]).format("YYYY-MM-DD HH:mm:ss");
console.log(start, end);
}
const onFinish = values => {
const start = moment(values.Picker[0]).format("YYYY-MM-DD HH:mm:ss");
const end = moment(values.Picker[1]).format("YYYY-MM-DD HH:mm:ss");
console.log(start, end)
};

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