Skip to content

Commit d485bfe

Browse files
authored
Pass dayPickerInput instance to onDayChange (#782)
* Pass `this` to `onDayChange` * Update type definition * Update docs * Fix unit tests
1 parent d4289ff commit d485bfe

File tree

5 files changed

+107
-51
lines changed

5 files changed

+107
-51
lines changed

docs/src/code-samples/examples/input-state.js

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,25 +8,31 @@ export default class Example extends React.Component {
88
this.handleDayChange = this.handleDayChange.bind(this);
99
this.state = {
1010
selectedDay: undefined,
11+
isEmpty: true,
1112
isDisabled: false,
1213
};
1314
}
14-
handleDayChange(selectedDay, modifiers) {
15+
16+
handleDayChange(selectedDay, modifiers, dayPickerInput) {
17+
const input = dayPickerInput.getInput();
1518
this.setState({
1619
selectedDay,
20+
isEmpty: !input.value.trim(),
1721
isDisabled: modifiers.disabled === true,
1822
});
1923
}
24+
2025
render() {
21-
const { selectedDay, isDisabled } = this.state;
26+
const { selectedDay, isDisabled, isEmpty } = this.state;
2227
return (
2328
<div>
2429
<p>
25-
{!selectedDay && '🤔 Type or pick a valid day'}
26-
{selectedDay && isDisabled && '😡 This day is disabled'}
30+
{isEmpty && 'Please type or pick a day'}
31+
{!isEmpty && !selectedDay && 'This day is invalid'}
32+
{selectedDay && isDisabled && 'This day is disabled'}
2733
{selectedDay &&
2834
!isDisabled &&
29-
`😄 You chose ${selectedDay.toLocaleDateString()}`}
35+
`You chose ${selectedDay.toLocaleDateString()}`}
3036
</p>
3137
<DayPickerInput
3238
value={selectedDay}

docs/src/pages/api/DayPickerInput.js

Lines changed: 51 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,13 @@ export default () => (
1717
<a href="#classNames">classNames</a>,{' '}
1818
<a href="#clickUnselectsDay">clickUnselectsDay</a>,{' '}
1919
<a href="#component">component</a>,{' '}
20-
<a href="#dayPickerProps">dayPickerProps</a>, <a href="#format">format</a>,{' '}
21-
<a href="#formatDate">formatDate</a>, <a href="#keepFocus">keepFocus</a>,{' '}
22-
<a href="#hideOnDayClick">hideOnDayClick</a>,{' '}
20+
<a href="#dayPickerProps">dayPickerProps</a>, <a href="#format">format</a>
21+
, <a href="#formatDate">formatDate</a>, <a href="#keepFocus">keepFocus</a>
22+
, <a href="#hideOnDayClick">hideOnDayClick</a>,{' '}
2323
<a href="#inputProps">inputProps</a>,{' '}
2424
<a href="#overlayComponent">overlayComponent</a>,{' '}
25-
<a href="#parseDate">parseDate</a>, <a href="#placeholder">placeholder</a>,{' '}
26-
<a href="#showOverlay">showOverlay</a>, <a href="#value">value</a>
25+
<a href="#parseDate">parseDate</a>, <a href="#placeholder">placeholder</a>
26+
, <a href="#showOverlay">showOverlay</a>, <a href="#value">value</a>
2727
</p>
2828
<h4>Event handlers</h4>
2929
<p>
@@ -32,8 +32,8 @@ export default () => (
3232
</p>
3333
<h4>Public methods</h4>
3434
<p>
35-
<a href="#getDayPicker">getDayPicker</a>, <a href="#getInput">getInput</a>,{' '}
36-
<a href="#hideDayPicker">hideDayPicker</a>,{' '}
35+
<a href="#getDayPicker">getDayPicker</a>, <a href="#getInput">getInput</a>
36+
, <a href="#hideDayPicker">hideDayPicker</a>,{' '}
3737
<a href="#showDayPicker">showDayPicker</a>
3838
</p>
3939
<hr />
@@ -118,11 +118,13 @@ export default () => (
118118
prop, while <code>locale</code> is from{' '}
119119
<a href="#dayPickerProps">
120120
<code>dayPickerProps</code>
121-
</a>.<br />
121+
</a>
122+
.<br />
122123
See also{' '}
123124
<a href="#parseDate">
124125
<code>parseDate</code>
125-
</a>.
126+
</a>
127+
.
126128
</p>
127129
<p>
128130
If you are using <a href="http://momentjs.com/">moment.js</a> in your
@@ -221,19 +223,21 @@ function MyDayPickerInput() {
221223
</h3>
222224
<p>
223225
Date parser used for parsing the string typed in the input field. As
224-
default, it parses only dates formatted as <code>YYYY-M-D</code>.
225-
<br />
226+
default, it parses only dates formatted as <code>YYYY-M-D</code>.<br />
226227
Arguments: <code>format</code> is the value coming from the{' '}
227228
<a href="#format">
228229
<code>format</code>
229230
</a>{' '}
230231
prop, while <code>locale</code> is from{' '}
231232
<a href="#dayPickerProps">
232233
<code>dayPickerProps</code>
233-
</a>.<br />See also{' '}
234+
</a>
235+
.<br />
236+
See also{' '}
234237
<a href="#formatDate">
235238
<code>formatDate</code>
236-
</a>.
239+
</a>
240+
.
237241
</p>
238242
<p>
239243
If you are using <a href="http://momentjs.com/">moment.js</a> in your
@@ -269,18 +273,43 @@ function MyDayPickerInput() {
269273

270274
<h3>
271275
<Anchor id="onDayChange" />
272-
onDayChange <code>(day: ?Date, modifiers: Object) ⇒ void</code>
276+
onDayChange{' '}
277+
<code>
278+
(day: ?Date, modifiers: Object, dayPickerInput: DayPickerInput) ⇒ void
279+
</code>
273280
</h3>
274281
<p>
275-
Handler function called when the user types a valid day – according to
276-
the{' '}
277-
<code>
278-
<a href="#format">format</a>
279-
</code>{' '}
280-
prop – or when a day is clicked on the calendar. If the typed value is
281-
empty or not valid, `day` is <code>undefined</code> and `modifiers` is
282-
an empty object.
282+
Handler function called when the user types into the input field or when
283+
a day is clicked on the calendar.
284+
</p>
285+
<p>
286+
<strong>Implementation Notes</strong>
283287
</p>
288+
<ul>
289+
<li>
290+
If the typed value is empty or not valid, <code>day</code> is{' '}
291+
<code>undefined</code> and <code>modifiers</code> is an empty object.
292+
</li>
293+
<li>
294+
The third argument is the DayPickerInput instance. You can use it to
295+
access to the instance props or public methods
296+
</li>
297+
</ul>
298+
<CodeBlock>{`handleDayChange(selectedDay, modifiers, dayPickerInput) {
299+
const input = dayPickerInput.getInput();
300+
this.setState({
301+
selectedDay,
302+
isEmpty: !input.value.trim(),
303+
isValidDay: typeof selectedDay !== 'undefined',
304+
isDisabled: modifiers.disabled === true,
305+
});
306+
}
307+
308+
<DayPickerInput
309+
onDayChange={handleDayChange}
310+
selectedDay={this.state.selectedDay}
311+
/>`}</CodeBlock>
312+
284313
<h3>
285314
<Anchor id="onDayPickerHide" />
286315
onDayPickerHide <code>() ⇒ void</code>

src/DayPickerInput.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,7 @@ export default class DayPickerInput extends React.Component {
284284
}),
285285
{}
286286
);
287-
onDayChange(day, modifiers);
287+
onDayChange(day, modifiers, this);
288288
});
289289
}
290290

@@ -405,14 +405,14 @@ export default class DayPickerInput extends React.Component {
405405
const { value } = e.target;
406406
if (value.trim() === '') {
407407
this.setState({ value, typedValue: undefined });
408-
if (onDayChange) onDayChange(undefined, {});
408+
if (onDayChange) onDayChange(undefined, {}, this);
409409
return;
410410
}
411411
const day = parseDate(value, format, dayPickerProps.locale);
412412
if (!day) {
413413
// Day is invalid: we save the value in the typedValue state
414414
this.setState({ value, typedValue: value });
415-
if (onDayChange) onDayChange(undefined, {});
415+
if (onDayChange) onDayChange(undefined, {}, this);
416416
return;
417417
}
418418
this.updateState(day, value);
@@ -491,15 +491,15 @@ export default class DayPickerInput extends React.Component {
491491
this.hideAfterDayClick
492492
);
493493
if (onDayChange) {
494-
onDayChange(undefined, modifiers);
494+
onDayChange(undefined, modifiers, this);
495495
}
496496
return;
497497
}
498498

499499
const value = formatDate(day, format, dayPickerProps.locale);
500500
this.setState({ value, typedValue: undefined, month: day }, () => {
501501
if (onDayChange) {
502-
onDayChange(day, modifiers);
502+
onDayChange(day, modifiers, this);
503503
}
504504
this.hideAfterDayClick();
505505
});

test/daypickerinput/events.js

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,11 @@ describe('DayPickerInput', () => {
113113
const wrapper = mount(<DayPickerInput onDayChange={onDayChange} />);
114114
const input = wrapper.find('input');
115115
input.simulate('change', { target: { value: '' } });
116-
expect(onDayChange).toHaveBeenCalledWith(undefined, {});
116+
expect(onDayChange).toHaveBeenCalledWith(
117+
undefined,
118+
{},
119+
expect.anything()
120+
);
117121
});
118122
it("should update the input's value if the value is not a valid date", () => {
119123
const wrapper = mount(<DayPickerInput />);
@@ -126,7 +130,11 @@ describe('DayPickerInput', () => {
126130
const wrapper = mount(<DayPickerInput onDayChange={onDayChange} />);
127131
const input = wrapper.find('input');
128132
input.simulate('change', { target: { value: 'foo' } });
129-
expect(onDayChange).toHaveBeenCalledWith(undefined, {});
133+
expect(onDayChange).toHaveBeenCalledWith(
134+
undefined,
135+
{},
136+
expect.anything()
137+
);
130138
});
131139
it("should update the input's value and the displayed month", () => {
132140
const wrapper = mount(<DayPickerInput />);
@@ -344,10 +352,14 @@ describe('DayPickerInput', () => {
344352
.find('.DayPicker-Day')
345353
.at(10)
346354
.simulate('click');
347-
expect(onDayChange).toHaveBeenCalledWith(undefined, {
348-
selected: true,
349-
foo: true,
350-
});
355+
expect(onDayChange).toHaveBeenCalledWith(
356+
undefined,
357+
{
358+
selected: true,
359+
foo: true,
360+
},
361+
expect.anything()
362+
);
351363
});
352364
it('should call `onDayChange` when typing an invalid day', () => {
353365
const onDayChange = jest.fn();
@@ -359,7 +371,11 @@ describe('DayPickerInput', () => {
359371
.find('input')
360372
.simulate('change', { target: { value: '02/07/x' } });
361373
wrapper.update();
362-
expect(onDayChange).toHaveBeenCalledWith(undefined, {});
374+
expect(onDayChange).toHaveBeenCalledWith(
375+
undefined,
376+
{},
377+
expect.anything()
378+
);
363379
wrapper.setState({ typedValue: '02/07/x', value: '' });
364380
expect(wrapper.state('typedValue')).toBe('02/07/x');
365381
expect(wrapper.find('input')).toHaveProp('value', '02/07/x');

types/props.d.ts

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import * as React from 'react';
44
import { ClassNames, Modifier, Modifiers, DayModifiers } from './common';
55
import { LocaleUtils } from './utils';
6+
import { DayPickerInput } from './DayPickerInput';
67

78
export interface CaptionElementProps {
89
date: Date;
@@ -39,14 +40,14 @@ export interface WeekdayElementProps {
3940
export interface DayPickerProps {
4041
canChangeMonth?: boolean;
4142
captionElement?:
42-
| React.ReactElement<Partial<CaptionElementProps>>
43-
| React.ComponentClass<CaptionElementProps>
44-
| React.SFC<CaptionElementProps>;
43+
| React.ReactElement<Partial<CaptionElementProps>>
44+
| React.ComponentClass<CaptionElementProps>
45+
| React.SFC<CaptionElementProps>;
4546
className?: string;
4647
classNames?: ClassNames;
4748
containerProps?: React.DetailedHTMLProps<
48-
React.HTMLAttributes<HTMLDivElement>,
49-
HTMLDivElement
49+
React.HTMLAttributes<HTMLDivElement>,
50+
HTMLDivElement
5051
>;
5152
disabledDays?: Modifier | Modifier[];
5253
showOutsideDays?: boolean;
@@ -76,9 +77,9 @@ export interface DayPickerProps {
7677
string
7778
];
7879
navbarElement?:
79-
| React.ReactElement<Partial<NavbarElementProps>>
80-
| React.ComponentClass<NavbarElementProps>
81-
| React.SFC<NavbarElementProps>;
80+
| React.ReactElement<Partial<NavbarElementProps>>
81+
| React.ComponentClass<NavbarElementProps>
82+
| React.SFC<NavbarElementProps>;
8283
numberOfMonths?: number;
8384
onBlur?(e: React.FocusEvent<HTMLDivElement>): void;
8485
onCaptionClick?(month: Date, e: React.MouseEvent<HTMLDivElement>): void;
@@ -145,9 +146,9 @@ export interface DayPickerProps {
145146
todayButton?: string;
146147
toMonth?: Date;
147148
weekdayElement?:
148-
| React.ReactElement<Partial<WeekdayElementProps>>
149-
| React.ComponentClass<WeekdayElementProps>
150-
| React.SFC<WeekdayElementProps>;
149+
| React.ReactElement<Partial<WeekdayElementProps>>
150+
| React.ComponentClass<WeekdayElementProps>
151+
| React.SFC<WeekdayElementProps>;
151152
weekdaysLong?: [string, string, string, string, string, string, string];
152153
weekdaysShort?: [string, string, string, string, string, string, string];
153154
}
@@ -174,7 +175,11 @@ export interface DayPickerInputProps {
174175

175176
classNames?: ClassNames;
176177

177-
onDayChange?(day: Date, DayModifiers: DayModifiers): void;
178+
onDayChange?(
179+
day: Date,
180+
DayModifiers: DayModifiers,
181+
dayPickerInput: DayPickerInput
182+
): void;
178183
onDayPickerHide?(): void;
179184
onChange?(e: React.FocusEvent<HTMLDivElement>): void;
180185
onClick?(e: React.FocusEvent<HTMLDivElement>): void;

0 commit comments

Comments
 (0)