13

I am using react-datetime for our calendar control.Now the issue is that if the user entered an invalid date like 'djfdjfhjkhdf' then in this control nothing is there to validate.So I decided to write my own validation function and call that on blur event if the date is invalid then clear the text entered by the user.My code is like this:-

import DatePicker from 'react-datetime';

focousOut(value) {
if (!validateDate(value)) {
  this.setState({ startDate:  ''});
  this.setState({ selectedValue: '' });
 }
}
handleChange(date) {
 this.setState({ selectedValue: date });
 this.setState({ startDate: date });
}

<Datetime
  timeFormat={false}
  value={this.state.selectedValue}
  defaultValue={this.state.startDate}
  onChange={this.handleChange}
  onBlur={this.focousOut}
  locale='en-US'
  dateFormat
  closeOnSelect
/>
Gorakh Nath
  • 9,140
  • 15
  • 46
  • 68
  • have you tried setting `this.state.selectedValue` to a empty string? – bennygenel Sep 05 '17 at 10:56
  • @bennygenel I tried it but not working, I modified my focus out function in above question.Still it's not working. – Gorakh Nath Sep 05 '17 at 11:01
  • you can set the date to today or another default date when the date is not valid I thing but don't know how you can clear all the input. – bennygenel Sep 05 '17 at 11:02
  • You don't need to use multiple `setState` by the way. For example, just do: `this.setState({startDate: '', selectedValue: ''});` – Chris Sep 05 '17 at 11:02
  • @Chris yes no need to set multiple setState, I agreed but it won't solve above scenario. – Gorakh Nath Sep 05 '17 at 11:05
  • @bennygenel by setting to other value will not be clear for the users.We have to clear the text if entered invalid date and then allow to select and enter date again. – Gorakh Nath Sep 05 '17 at 11:07

2 Answers2

10

Yeah, there's clearly a rendering bug in component if you try to pass a null or empty value in controlled component mode: the internal input still got the former value entered with the calendar (uncontrolled ?) despite the fact that that.state.value is null : I've been able to "patch" it with the renderInput prop :

<Datetime
   value={(this.state.date) ? this.state.date : ''} 
   onChange={(value) => { this.setState{(date : ((value) && (isNaN(new Date(value)) === false)) ? new Date(value)).format('yyyy-mm-dd')  null, attribute) }} 
   renderInput={(props) => {
       return <input {...props} value={(this.state.date) ? props.value : ''} />
   }}
/>
                                                
  • 1
    Thank you so much!!!! I was suffering from the same bug and your answer saved my night... – Chen Ni Feb 02 '21 at 13:24
  • This still seems to be the case, if you're binding the value to state and then having it as either null or empty string, it doesn't render the field empty unless you have renderInput defined as well, which is a bit unfortunate. – mpartan Jan 18 '22 at 14:46
7

One of the issues seem to be that, based on the given props, you are creating a mix of a controlled and uncontrolled Datetime component. Basically, use value if you want a state-controlled component, or defaultValue to let the DOM manage the input value.

See this part of the documentation:

value - Represents the selected date by the component, in order to use it as a controlled component. This prop is parsed by Moment.js, so it is possible to use a date string or a moment object.

defaultValue - Represents the selected date for the component to use it as a uncontrolled component. This prop is parsed by Moment.js, so it is possible to use a date string or a moment object.


Have a look at this forked codepen I made.

var date = new Date();

class App extends React.Component {
  constructor() {
    super();
    this.state = {selectedValue: ''};
    this.focousOut = this.focousOut.bind(this);
    this.handleChange = this.handleChange.bind(this);
  }
  
  focousOut(value) {
    if(!moment(value).isValid()) {
     this.setState({selectedValue: ''}); 
    }
  }
  
  handleChange(date) {
   this.setState({ selectedValue: date });
  }

  render() {
    return (
       <Datetime
         timeFormat={false}
         value={this.state.selectedValue}
         onChange={this.handleChange}
         onBlur={this.focousOut}
         locale='en-US'
         dateFormat
         closeOnSelect
       />
    );
  }
}

React.render(<App />, document.body);

Also, you can use the moment.js library to easily determine if a string is of a valid Date format. Just use moment().isValid().

I should note that the onBlur event seems to trigger on the 2nd blur. Not sure why that is, but perhaps the you'll find an answer in the docs. The above is only a fix to your existing code, and hopefully a useful guideline to get you started.

Community
  • 1
  • 1
Chris
  • 57,622
  • 19
  • 111
  • 137
  • By the way, it's *"focus"*, not *"focous"*. ;) – Chris Sep 05 '17 at 11:32
  • Yes, it should be the focus, but still, it's not clearing the invalid date.I think it is not possible in this control to clear the selected or entered a value. – Gorakh Nath Sep 05 '17 at 12:01
  • I tried in forked codepen that you have added above but it is not clearing the value.You can check that by writing djfhdjhf and do focus out from control.Now it should clear that value, but the value remains the same – Gorakh Nath Sep 05 '17 at 12:07
  • @jack123, yes, like I said. For some reason it clears it the second time you blur. Try it again but this time focus and blur a couple of times. – Chris Sep 05 '17 at 12:11
  • 1
    I think this control have limited options, we can't do this. – Gorakh Nath Sep 05 '17 at 12:17
  • @jack123, alright. Did this answer your question though? – Chris Sep 05 '17 at 12:23
  • yes, but above answer will be useful for the beginner to use the react-datetime, thats why I am making vote up for the answer. – Gorakh Nath Sep 05 '17 at 12:35
  • I prefer ``` handleBlur = (date) => { if (!moment(date).isValid()) { this.setState(prevstate => ({ value: prevstate.value, })) } }``` – Donnie Ashok Mar 22 '19 at 14:29