Material-ui: DatePicker has no way to clear it

Created on 28 Aug 2015  路  26Comments  路  Source: mui-org/material-ui

I am trying to clear the datepicker. The best I can do is:
this.refs.myDatePicker.setDate();

which clears the field. however
this.refs.myDatePicker.getDate();
still gives me the date. Is there a way to remove the date from it?

v0.x

Most helpful comment

@nathanmarks I'd like to suggest that the DatePicker component be changed to have a clearable prop, and if set to true, an "x" will be rendered, similar to the Select component.

All 26 comments

Im struggling with this at the moment as well. I've noticed that the following will log undefined to the console.

this.refs.myDatePicker.setDate();
setTimeout(() => {
    console.log(this.refs.myDatePicker.getDate());
}, 2000);

However, if I remove the timeout I get the actual date value as well.

The problem occurs because reacts setState is asynchronous. I solved it by creating a higher order component for DatePicker, which is ClearableDatePicker. This higher order component manually reaches into setState of DatePicker and sets date = undefined. I then wait for the callback method and manually fire the onChange event for DatePicker. Like this:

const Clearable = ComposedComponent => class extends React.Component {
  clearDate (event) {
    event.preventDefault();

    // We manually reach into the composed component and set it's date to undefined.
    let newDate;
    this.refs.datePicker.setState({
      date: newDate
    }, () => {
      this.refs.datePicker.props.onChange(null, newDate);
    });
  }

  render () {
    return (
      <div className='datepicker'>
        <ComposedComponent { ...this.props } ref="datePicker" />
        { this.renderClearButton() }
      </div>
    )
  }

  renderClearButton () {
    if (this.refs.datePicker && this.refs.datePicker.getDate()) {
      return <button className='clear' onClick={ ::this.clearDate }>X</button>;
    }
  }
}

export default Clearable(DatePicker);

_Disclaimer:_ This higher order component requires me to manually redefine getDate again in order use it for when using my component. There is probably a way of solving this, I have not found a solution for that yet though.

I ended up doing this, thought its bad.

this.refs.myDatePicker.setDate();
this.refs.myDataPicker.state.date = null;

probably shouldn't do that.

Notice, in the upcoming version of [email protected], we can no longer do stuff like

this.refs.myDatePicker.setDate();

Edit
Turn out we can!

@oliviertassinari What is a valid future proof approach to clearing the date then? Do you know any?

A workaround I've used when I need to reset the state of a child component is changing its key - which forces the component to remount and, therefore, reinitialize it's state.

@oliviertassinari You can use refs. Check out this gist: https://gist.github.com/jkruder/52a2f88eb38ff6c0fec8

@jkruder Oh great, my bad! Now I understand what this mean from their blog

Refs to custom component classes work exactly as before

Having this issue here, @Pendla approach almost works, except after reseting the component the text doens't clears up, I'm using floatingText, the floating text goes back to it's original position but the old value still present there.

@nathanmarks I'd like to suggest that the DatePicker component be changed to have a clearable prop, and if set to true, an "x" will be rendered, similar to the Select component.

Hey @ajsharp ,

I think that DatePicker could simply be something that you "attach" to a TextField, leaving that part of the component to be composable.

@nathanmarks Why? It's less code for the user of this library to say "give me a datepicker with these options". What benefit to the user is being "composable" in this instance?

@ajsharp If we followed that principle for everything, the library would be extremely limited. We're talking about a couple of lines of code here, not entire components the user has to implement themselves.

I just flicked through my nexus 6p and found multiple instances of date and time pickers that are not hooked up to material form style text fields -- or anything similar visually (apart from having text). For eg, in the android stock alarm application, the time is just a big number (very large heading size) that you tap and it pops open a time picker.

To do that with our time picker, you'd have to override styles up the ying yang. Seems pointless using a material-ui TextField if you don't actually want a material text input with all the form styling.

I've ended up succeeding using datePicker with the new Field API from redux-form and with a clearable button.
I had to use null value for resetting the datePicker and not undefined. I also use Moment for dealing with UTC date (It should be the default behaviur by the way).
I''d like to thank you people in this thread for the inspiration and explanation.

Clearable Component :

import React, {Component} from 'react';
import Moment from 'moment';
import DatePicker from 'material-ui/DatePicker';
import IconButton from 'material-ui/IconButton';
import Clear from 'material-ui/svg-icons/content/clear';

const Clearable = ComposedComponent => class extends React.Component {

    onChange(evt, date) {
        if (this.props.input.onChange) {
            this.props.input.onChange(date ? Moment.utc(Moment(date).format('YYYY-MM-DD[T]HH:mm:ss')).toDate() : null);
        }
    }

    clearDate (event) {
        event.preventDefault();

        // We manually reach into the composed component and set it's date to null.
        let newDate = null;
        this.refs.datePicker.setState({
            date: newDate
        }, () => {
            this.refs.datePicker.props.onChange(null, newDate);
        });
    }
    render () {
        return (
            <div style={{position: 'relative'}}>
                <ComposedComponent
                    { ...this.props.input }
                    autoOk={true}
                    container="inline"
                    ref="datePicker"
                    value={this.props.input.value ? new Date(this.props.input.value) : null}
                    onChange={this.onChange.bind(this)}/>
                {this.props.input.value &&
                <IconButton ref="button" onClick={this.clearDate.bind(this)} style={{position: 'absolute', top: '6px',right: '4px', padding: '0', width: '24px', height: '24px'}}>
                    <Clear />
                </IconButton>
                }
            </div>
        )
    }
};

export default Clearable(DatePicker);

And you can use it like that:

import DatePickerInput from './DatePickerInput';

<Field name="date" component={DatePickerInput} hintText="Date"/>

Hope it will help folks ;)

So, is a a higher order component the only way to clear the DatePicker? I think it would be nicer if it cleared when you set the value property as null.

I ended up with pure functional component like this:

import React from 'react';
import DatePicker from 'material-ui/DatePicker';
import MUI_SquareFlatBtn from '/client/modules/genericComponents/components/MUI_SquareFlatBtn';


export default function MUI_DatePickerClearable({context, style, clearIcon, datePickerStyle={}, ...datePickerProps}) {

  function clearBtnClickWrapper() {
    datePickerProps.onChange(null, null); // (event, newValue)
  }

  return (
    <div
      style={{
        display: 'flex',
        flexDirection: 'row',
        alignItems: 'flex-end'
      }}
    >
      <div style={{flexGrow: '1'}}>
        <DatePicker
          style={datePickerStyle}
          {...datePickerProps}
          fullWidth={true}
        />
      </div>
      <div>
        <MUI_SquareFlatBtn
          icon={clearIcon}
          onTouchTap={clearBtnClickWrapper}
        />
      </div>
    </div>
  );
}

The value is passed to date picker inside datePickerProps

Needed a quick and dirty way to do it would be something like

[...document.querySelectorAll('input[name=date-timestamp]')].forEach(input => {
  console.log(input.value);
   input.value = '';
});

I would think this would work....but some reason that I am not able to get...its not working.
console.log returns the correct value, but setting the value no longer works.

So back again 2 years later. Here is my current dirty solution:
(this is a piece of a bigger whole)

const DateRange = ({ order, changeStartDate, changeEndDate, startDate, endDate }) => {
    let minDateRef, maxDateRef
    return <div className="row center-xs leaderboards" >
            <Paper className="col-xs-10 col-sm-8 col-md-6">
                <div style={dateRangeContainerStyle}>
                    <div style={dateRangeStyle}>
                        <DatePicker ref={(ref) => minDateRef = ref} floatingLabelText="Min Date" autoOk onChange={changeStartDate} formatDate={formatDate} />
                        <Close style={closeStyle} onTouchTap={() => {
                            changeStartDate()
                            minDateRef.setState({ date: null })
                        }} />
                    </div>
                    <div style={dateRangeStyle}>
                        <DatePicker ref={(ref) => maxDateRef = ref} floatingLabelText="Max Date" autoOk onChange={changeEndDate} formatDate={formatDate} />
                        <Close style={closeStyle} onTouchTap={() => {
                            changeEndDate()
                            maxDateRef.setState({ date: null })
                        }} />
                    </div>
                </div>
            </div>
        </Paper>
    </div>  
}

@pr1ntr You can check this comment https://github.com/callemall/material-ui/issues/4952#issuecomment-273845579 regarding clearable fields. This is old code, but I'm sure it will help you making clear and concise code using the HOC pattern :)

Why closed? There is still no way to set value as null and see empty field.

@Ohar v0.x is in a low maintenance mode. Put it more simply, 97% of the effort is on v1.x right now.

@oliviertassinari Oh, is it only for v0.x?

  1. Just make a ref in DatePicker. (e.g. ref="datePicker")
  2. And try these to clear :
    this.refs.datePicker.picker.state.showDate = null
    this.refs.datePicker.picker.state.value = null
  1. Just make a ref in DatePicker. (e.g. ref="datePicker")
  2. And try these to clear :
    this.refs.datePicker.picker.state.showDate = null
    this.refs.datePicker.picker.state.value = null

It Helped!

Adding on to waahab, I was able to access DatePicker through this.refs.datePicker.state. To get the input value I accessed this.refs.datePicker.state.inputValue

I found this turnaround to clear it :

  • Pass by the DOM and set value to null
  • Define InputValue in the same time (it overwrites value if it's defined)

Thus it goes like this :

  1. Clear the DOM at each render to be sure it doesn't come back :
useEffect(() => {
    if (value === null) {
      const datepicker = document.getElementById("your-id");
      datepicker.value = null;
    }
  });
  1. In KeyBoardDatePicker, add this prop :
    inputValue={value === null ? null : undefined}
Was this page helpful?
0 / 5 - 0 ratings

Related issues

ericraffin picture ericraffin  路  3Comments

finaiized picture finaiized  路  3Comments

sys13 picture sys13  路  3Comments

zabojad picture zabojad  路  3Comments

FranBran picture FranBran  路  3Comments