From c276ecf7e6e9cc40656028f2ea69e1f2555d66c9 Mon Sep 17 00:00:00 2001 From: Suvish Varghese Thoovamalayil Date: Mon, 27 Nov 2017 17:25:06 +0530 Subject: [PATCH] Allow specifying viewDate as a prop, fixes #468 Optionally specify the month that is viewed when opening the date picker without having an explicit value set. The default behavior of `viewDate` is retained as well. --- DateTime.d.ts | 5 +++++ DateTime.js | 26 ++++++++++++++++-------- README.md | 1 + react-datetime.d.ts | 5 +++++ test/testUtils.js | 4 ++++ test/tests.spec.js | 49 +++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 82 insertions(+), 8 deletions(-) diff --git a/DateTime.d.ts b/DateTime.d.ts index 50b9cf332..ae2a8b930 100644 --- a/DateTime.d.ts +++ b/DateTime.d.ts @@ -41,6 +41,11 @@ declare namespace ReactDatetimeClass { This prop is parsed by moment.js, so it is possible to use a date string or a moment.js date. */ defaultValue?: Date | string | Moment; + /* + Represents the month which is viewed on opening the calendar when there is no selected date. + This prop is parsed by Moment.js, so it is possible to use a date `string` or a `moment` object. + */ + viewDate?: Date | string | Moment; /* Defines the format for the date. It accepts any moment.js date format. If true the date will be displayed using the defaults for the current locale. diff --git a/DateTime.js b/DateTime.js index 1a7d6e6fc..1259287ed 100644 --- a/DateTime.js +++ b/DateTime.js @@ -13,6 +13,7 @@ var Datetime = createClass({ propTypes: { // value: TYPES.object | TYPES.string, // defaultValue: TYPES.object | TYPES.string, + // viewDate: TYPES.object | TYPES.string, onFocus: TYPES.func, onBlur: TYPES.func, onChange: TYPES.func, @@ -43,24 +44,33 @@ var Datetime = createClass({ return state; }, + parseDate: function (date, formats) { + var parsedDate; + + if (date && typeof date === 'string') + parsedDate = this.localMoment(date, formats.datetime); + else if (date) + parsedDate = this.localMoment(date); + + if (parsedDate && !parsedDate.isValid()) + parsedDate = null; + + return parsedDate; + }, + getStateFromProps: function( props ) { var formats = this.getFormats( props ), date = props.value || props.defaultValue, selectedDate, viewDate, updateOn, inputValue ; - if ( date && typeof date === 'string' ) - selectedDate = this.localMoment( date, formats.datetime ); - else if ( date ) - selectedDate = this.localMoment( date ); + selectedDate = this.parseDate(date, formats); - if ( selectedDate && !selectedDate.isValid() ) - selectedDate = null; + viewDate = this.parseDate(props.viewDate, formats); viewDate = selectedDate ? selectedDate.clone().startOf('month') : - this.localMoment().startOf('month') - ; + viewDate ? viewDate.clone().startOf('month') : this.localMoment().startOf('month'); updateOn = this.getUpdateOn(formats); diff --git a/README.md b/README.md index b259cabdd..16b7835ba 100644 --- a/README.md +++ b/README.md @@ -43,6 +43,7 @@ render: function() { | ------------ | ------- | ------- | ----------- | | **value** | `Date` | `new Date()` | Represents the selected date by the component, in order to use it as a [controlled component](https://facebook.github.io/react/docs/forms.html#controlled-components). This prop is parsed by Moment.js, so it is possible to use a date `string` or a `moment` object. | | **defaultValue** | `Date` | `new Date()` | Represents the selected date for the component to use it as a [uncontrolled component](https://facebook.github.io/react/docs/uncontrolled-components.html). This prop is parsed by Moment.js, so it is possible to use a date `string` or a `moment` object. | +| **viewDate** | `Date` | `new Date()` | Represents the month which is viewed on opening the calendar when there is no selected date. This prop is parsed by Moment.js, so it is possible to use a date `string` or a `moment` object. | | **dateFormat** | `boolean` or `string` | `true` | Defines the format for the date. It accepts any [Moment.js date format](http://momentjs.com/docs/#/displaying/format/) (not in localized format). If `true` the date will be displayed using the defaults for the current locale. If `false` the datepicker is disabled and the component can be used as timepicker, see [available units docs](#specify-available-units). | | **timeFormat** | `boolean` or `string` | `true` | Defines the format for the time. It accepts any [Moment.js time format](http://momentjs.com/docs/#/displaying/format/) (not in localized format). If `true` the time will be displayed using the defaults for the current locale. If `false` the timepicker is disabled and the component can be used as datepicker, see [available units docs](#specify-available-units). | | **input** | `boolean` | `true` | Whether to show an input field to edit the date manually. | diff --git a/react-datetime.d.ts b/react-datetime.d.ts index d8d4a44ad..d99491472 100644 --- a/react-datetime.d.ts +++ b/react-datetime.d.ts @@ -22,6 +22,11 @@ declare module ReactDatetime { This prop is parsed by moment.js, so it is possible to use a date string or a moment.js date. */ defaultValue?: Date; + /* + Represents the month which is viewed on opening the calendar when there is no selected date. + This prop is parsed by Moment.js, so it is possible to use a date `string` or a `moment` object. + */ + viewDate?: Date; /* Defines the format for the date. It accepts any moment.js date format. If true the date will be displayed using the defaults for the current locale. diff --git a/test/testUtils.js b/test/testUtils.js index 9af50a624..da83a23f8 100644 --- a/test/testUtils.js +++ b/test/testUtils.js @@ -120,5 +120,9 @@ module.exports = { getInputValue: (datetime) => { return datetime.find('.rdt > .form-control').getDOMNode().value; + }, + + getViewDateValue: (datetime) => { + return datetime.find('.rdtSwitch').getDOMNode().innerHTML; } }; diff --git a/test/tests.spec.js b/test/tests.spec.js index 883f7ca0c..c15640000 100644 --- a/test/tests.spec.js +++ b/test/tests.spec.js @@ -1174,4 +1174,53 @@ describe('Datetime', () => { }); }); + + describe('with viewDate', () => { + it('date value', () => { + const date = new Date(2000, 0, 15, 2, 2, 2, 2), + strDate = moment(date).format('MMMM YYYY'), + component = utils.createDatetime({ viewDate: date }); + expect(utils.getViewDateValue(component)).toEqual(strDate); + }); + + it('moment value', () => { + const date = new Date(2000, 0, 15, 2, 2, 2, 2), + mDate = moment(date), + strDate = mDate.format('MMMM YYYY'), + component = utils.createDatetime({ viewDate: mDate }); + expect(utils.getViewDateValue(component)).toEqual(strDate); + }); + + it('string value', () => { + const date = new Date(2000, 0, 15, 2, 2, 2, 2), + mDate = moment(date), + strDate = mDate.format('L') + ' ' + mDate.format('LT'), + expectedStrDate = mDate.format('MMMM YYYY'), + component = utils.createDatetime({ viewDate: strDate }); + expect(utils.getViewDateValue(component)).toEqual(expectedStrDate); + }); + + it('UTC value from UTC string', () => { + const date = new Date(2000, 0, 15, 2, 2, 2, 2), + momentDateUTC = moment.utc(date), + strDateUTC = momentDateUTC.format('L') + ' ' + momentDateUTC.format('LT'), + expectedStrDate = momentDateUTC.format('MMMM YYYY'), + component = utils.createDatetime({ viewDate: strDateUTC, utc: true }); + expect(utils.getViewDateValue(component)).toEqual(expectedStrDate); + }); + + it('invalid string value', () => { + const strDate = 'invalid string', + expectedStrDate = moment().format('MMMM YYYY'), + component = utils.createDatetime({ viewDate: strDate }); + expect(utils.getViewDateValue(component)).toEqual(expectedStrDate); + }); + + it('invalid moment object', () => { + const mDate = moment(null), + expectedStrDate = moment().format('MMMM YYYY'), + component = utils.createDatetime({ viewDate: mDate }); + expect(utils.getViewDateValue(component)).toEqual(expectedStrDate); + }); + }); });