Skip to content

Commit 3c3ed45

Browse files
InvisibleBaconJakeThurman
authored andcommitted
Added onViewDateChange callback for when the viewed date changes
1 parent 7e30d6c commit 3c3ed45

File tree

4 files changed

+92
-14
lines changed

4 files changed

+92
-14
lines changed

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ Below we have all the props that we can use with the `<DateTime>` component. The
6767
| **onBeforeNavigate** | `function` | ( nextView, currentView, viewDate ) => nextView | Allows to intercept a change of the calendar view. The accepted function receives the view that it's supposed to navigate to, the view that is showing currently and the date currently shown in the view. Return a viewMode ( default ones are `years`, `months`, `days` or `time`) to navigate to it. If the function returns a "falsy" value, the navigation is stopped and we will remain in the current view. |
6868
| **onNavigateBack** | `function` | empty function | Callback trigger when the user navigates to the previous month, year or decade. The callback receives the amount and type ('month', 'year') as parameters. |
6969
| **onNavigateForward** | `function` | empty function | Callback trigger when the user navigates to the next month, year or decade. The callback receives the amount and type ('month', 'year') as parameters. |
70+
| **onViewDateChange** | `function` | empty function | Callback trigger for when the user changes the currently viewed date. The callback receives the current view date `moment` object as only parameter. |
7071
| **className** | `string` or `string array` | `''` | Extra class name for the outermost markup element. |
7172
| **inputProps** | `object` | `undefined` | Defines additional attributes for the input element of the component. For example: `onClick`, `placeholder`, `disabled`, `required`, `name` and `className` (`className` *sets* the class attribute for the input element). See [Customize the Input Appearance](#customize-the-input-appearance). |
7273
| **isValidDate** | `function` | `() => true` | Define the dates that can be selected. The function receives `(currentDate, selectedDate)` and shall return a `true` or `false` whether the `currentDate` is valid or not. See [selectable dates](#selectable-dates).|

src/DateTime.js

+20-14
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ export default class Datetime extends React.Component {
3131
onBeforeNavigate: TYPES.func,
3232
onNavigateBack: TYPES.func,
3333
onNavigateForward: TYPES.func,
34+
onViewDateChange: TYPES.func,
3435
updateOnView: TYPES.string,
3536
locale: TYPES.string,
3637
utc: TYPES.bool,
@@ -62,6 +63,7 @@ export default class Datetime extends React.Component {
6263
onBeforeNavigate: function(next) { return next; },
6364
onNavigateBack: nofn,
6465
onNavigateForward: nofn,
66+
onViewDateChange: nofn,
6567
dateFormat: true,
6668
timeFormat: true,
6769
utc: false,
@@ -445,25 +447,29 @@ export default class Datetime extends React.Component {
445447
}
446448
}
447449

448-
componentDidUpdate( prevProps ) {
449-
if ( prevProps === this.props ) return;
450+
componentDidUpdate( prevProps, prevState ) {
451+
if ( prevState.viewDate !== this.state.viewDate && !prevState.viewDate.isSame( this.state.viewDate ) ) {
452+
this.props.onViewDateChange( this.state.viewDate );
453+
}
450454

451-
let needsUpdate = false;
452-
let thisProps = this.props;
455+
if ( prevProps !== this.props ) {
456+
let needsUpdate = false;
457+
let thisProps = this.props;
453458

454-
['locale', 'utc', 'displayZone', 'dateFormat', 'timeFormat'].forEach( function(p) {
455-
prevProps[p] !== thisProps[p] && (needsUpdate = true);
456-
});
459+
['locale', 'utc', 'displayZone', 'dateFormat', 'timeFormat'].forEach( function(p) {
460+
prevProps[p] !== thisProps[p] && (needsUpdate = true);
461+
});
457462

458-
if ( needsUpdate ) {
459-
this.regenerateDates();
460-
}
463+
if ( needsUpdate ) {
464+
this.regenerateDates();
465+
}
461466

462-
if ( thisProps.value && thisProps.value !== prevProps.value ) {
463-
this.setViewDate( thisProps.value );
464-
}
467+
if ( thisProps.value && thisProps.value !== prevProps.value ) {
468+
this.setViewDate( thisProps.value );
469+
}
465470

466-
this.checkTZ();
471+
this.checkTZ();
472+
}
467473
}
468474

469475
regenerateDates() {

test/tests.spec.js

+66
Original file line numberDiff line numberDiff line change
@@ -1259,6 +1259,72 @@ describe('Datetime', () => {
12591259
});
12601260
});
12611261

1262+
describe('onViewDateChange', () => {
1263+
it('when increase month', () => {
1264+
const date = new Date(2000, 0, 15, 2, 2, 2, 2),
1265+
mDate = moment(date),
1266+
onViewDateChangeFn = jest.fn(),
1267+
component = utils.createDatetime({ initialViewDate: date, onViewDateChange: onViewDateChangeFn });
1268+
1269+
utils.clickOnElement(component.find('.rdtNext').at(0));
1270+
expect(onViewDateChangeFn).toHaveBeenCalledTimes(1);
1271+
expect(onViewDateChangeFn.mock.calls[0][0].isSame(mDate.add(1, 'month'), 'month')).toBeTruthy();
1272+
});
1273+
1274+
it('when decrease month', () => {
1275+
const date = new Date(2000, 0, 15, 2, 2, 2, 2),
1276+
mDate = moment(date),
1277+
onViewDateChangeFn = jest.fn(),
1278+
component = utils.createDatetime({ initialViewDate: date, onViewDateChange: onViewDateChangeFn });
1279+
1280+
utils.clickOnElement(component.find('.rdtPrev').at(0));
1281+
expect(onViewDateChangeFn).toHaveBeenCalledTimes(1);
1282+
expect(onViewDateChangeFn.mock.calls[0][0].isSame(mDate.subtract(1, 'month'), 'month')).toBeTruthy();
1283+
});
1284+
1285+
it('when pick month in picker', () => {
1286+
const date = new Date(2000, 0, 15, 2, 2, 2, 2),
1287+
mDate = moment(date),
1288+
onViewDateChangeFn = jest.fn(),
1289+
component = utils.createDatetime({ initialViewDate: date, initialViewMode: 'months', onViewDateChange: onViewDateChangeFn });
1290+
1291+
utils.clickNthMonth(component, 5);
1292+
expect(onViewDateChangeFn).toHaveBeenCalledTimes(1);
1293+
expect(onViewDateChangeFn.mock.calls[0][0].isSame(mDate.add(5, 'month'), 'month')).toBeTruthy();
1294+
});
1295+
1296+
it('when pick same month in picker', () => {
1297+
const date = new Date(2000, 0, 15, 2, 2, 2, 2),
1298+
onViewDateChangeFn = jest.fn(),
1299+
component = utils.createDatetime({ initialViewDate: date, initialViewMode: 'months', onViewDateChange: onViewDateChangeFn });
1300+
1301+
utils.clickNthMonth(component, 0);
1302+
expect(onViewDateChangeFn).not.toHaveBeenCalled();
1303+
});
1304+
1305+
it('when next is clicked in month view', () => {
1306+
const date = new Date(2000, 0, 15, 2, 2, 2, 2),
1307+
mDate = moment(date),
1308+
onViewDateChangeFn = jest.fn(),
1309+
component = utils.createDatetime({ initialViewDate: date, initialViewMode: 'months', onViewDateChange: onViewDateChangeFn });
1310+
1311+
utils.clickOnElement(component.find('.rdtNext').at(0));
1312+
expect(onViewDateChangeFn).toHaveBeenCalledTimes(1);
1313+
expect(onViewDateChangeFn.mock.calls[0][0].isSame(mDate.add(1, 'year'), 'year')).toBeTruthy();
1314+
});
1315+
1316+
it('when prev is clicked in month view', () => {
1317+
const date = new Date(2000, 0, 15, 2, 2, 2, 2),
1318+
mDate = moment(date),
1319+
onViewDateChangeFn = jest.fn(),
1320+
component = utils.createDatetime({ initialViewDate: date, initialViewMode: 'months', onViewDateChange: onViewDateChangeFn });
1321+
1322+
utils.clickOnElement(component.find('.rdtPrev').at(0));
1323+
expect(onViewDateChangeFn).toHaveBeenCalledTimes(1);
1324+
expect(onViewDateChangeFn.mock.calls[0][0].isSame(mDate.subtract(1, 'year'), 'year')).toBeTruthy();
1325+
});
1326+
});
1327+
12621328
describe('onNavigateBack', () => {
12631329
it('when moving to previous month', () => {
12641330
const component = utils.createDatetime({ onNavigateBack: (amount, type) => {

typings/DateTime.d.ts

+5
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,11 @@ declare namespace ReactDatetimeClass {
9696
to the user's local timezone (unless `utc` specified).
9797
*/
9898
displayTimeZone?: string;
99+
/*
100+
/*
101+
Callback trigger for when the user navigates the calendar
102+
*/
103+
onViewDateChange?: (value: Moment) => void;
99104
/*
100105
Callback trigger when the date changes. The callback receives the selected `moment` object as
101106
only parameter, if the date in the input is valid. If the date in the input is not valid, the

0 commit comments

Comments
 (0)