Skip to content
This repository was archived by the owner on Aug 29, 2025. It is now read-only.

Commit 74ed663

Browse files
authored
Merge pull request #948 from tcbegley/datepicker-disabled-days
Add disabled_days prop to datepickers
2 parents 76e97f7 + 1a890ab commit 74ed663

File tree

8 files changed

+111
-10
lines changed

8 files changed

+111
-10
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
66
## UNRELEASED
77
### Added
88
- [#932](https://github.com/plotly/dash-core-components/pull/932). Adds a new copy to clipboard component.
9+
- [#948](https://github.com/plotly/dash-core-components/pull/948)] Adds `disabled_days` prop to `DatePickerRange` and `DatePickerSingle` components. With this prop you can specify days that should be made unselectable in the date picker, in addition to those that fall outside of the range specified by `min_date_allowed` and `max_date_allowed`.
910

1011

1112
## [1.16.0] - 2021-04-08

src/components/DatePickerRange.react.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,13 @@ DatePickerRange.propTypes = {
7474
*/
7575
max_date_allowed: PropTypes.string,
7676

77+
/**
78+
* Specifies additional days between min_date_allowed and max_date_allowed
79+
* that should be disabled. Accepted datetime.datetime objects or strings
80+
* in the format 'YYYY-MM-DD'
81+
*/
82+
disabled_days: PropTypes.arrayOf(PropTypes.string),
83+
7784
/**
7885
* Specifies the month that is initially presented when the user
7986
* opens the calendar. Accepts datetime.datetime objects or strings
@@ -284,6 +291,7 @@ DatePickerRange.defaultProps = {
284291
updatemode: 'singledate',
285292
persisted_props: ['start_date', 'end_date'],
286293
persistence_type: 'local',
294+
disabled_days: [],
287295
};
288296

289297
export const propTypes = DatePickerRange.propTypes;

src/components/DatePickerSingle.react.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,13 @@ DatePickerSingle.propTypes = {
5454
*/
5555
max_date_allowed: PropTypes.string,
5656

57+
/**
58+
* Specifies additional days between min_date_allowed and max_date_allowed
59+
* that should be disabled. Accepted datetime.datetime objects or strings
60+
* in the format 'YYYY-MM-DD'
61+
*/
62+
disabled_days: PropTypes.arrayOf(PropTypes.string),
63+
5764
/**
5865
* Specifies the month that is initially presented when the user
5966
* opens the calendar. Accepts datetime.datetime objects or strings
@@ -240,6 +247,7 @@ DatePickerSingle.defaultProps = {
240247
disabled: false,
241248
persisted_props: ['date'],
242249
persistence_type: 'local',
250+
disabled_days: [],
243251
};
244252

245253
export const propTypes = DatePickerSingle.propTypes;

src/fragments/DatePickerRange.react.js

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -82,14 +82,20 @@ export default class DatePickerRange extends Component {
8282
}
8383

8484
isOutsideRange(date) {
85-
const {min_date_allowed, max_date_allowed} = convertToMoment(
86-
this.props,
87-
['min_date_allowed', 'max_date_allowed']
88-
);
85+
const {
86+
max_date_allowed,
87+
min_date_allowed,
88+
disabled_days,
89+
} = convertToMoment(this.props, [
90+
'max_date_allowed',
91+
'min_date_allowed',
92+
'disabled_days',
93+
]);
8994

9095
return (
9196
(min_date_allowed && date.isBefore(min_date_allowed)) ||
92-
(max_date_allowed && date.isAfter(max_date_allowed))
97+
(max_date_allowed && date.isAfter(max_date_allowed)) ||
98+
(disabled_days && disabled_days.some(d => date.isSame(d, 'day')))
9399
);
94100
}
95101

src/fragments/DatePickerSingle.react.js

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,20 @@ export default class DatePickerSingle extends Component {
1616
}
1717

1818
isOutsideRange(date) {
19-
const {max_date_allowed, min_date_allowed} = convertToMoment(
20-
this.props,
21-
['max_date_allowed', 'min_date_allowed']
22-
);
19+
const {
20+
max_date_allowed,
21+
min_date_allowed,
22+
disabled_days,
23+
} = convertToMoment(this.props, [
24+
'max_date_allowed',
25+
'min_date_allowed',
26+
'disabled_days',
27+
]);
2328

2429
return (
2530
(min_date_allowed && date.isBefore(min_date_allowed)) ||
26-
(max_date_allowed && date.isAfter(max_date_allowed))
31+
(max_date_allowed && date.isAfter(max_date_allowed)) ||
32+
(disabled_days && disabled_days.some(d => date.isSame(d, 'day')))
2733
);
2834
}
2935

src/utils/convertToMoment.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ export default (newProps, momentProps) => {
1919
undefined
2020
);
2121
}
22+
} else if (Array.isArray(value)) {
23+
dest[key] = value.map(d => moment(d));
2224
} else {
2325
dest[key] = moment(value);
2426

tests/integration/calendar/test_date_picker_range.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,3 +109,39 @@ def test_dtpr004_max_and_min_dates_are_clickable(dash_dcc):
109109
'#dps-initial-month .DateInput_input.DateInput_input_1[placeholder="End Date"]',
110110
"01/20/2021",
111111
)
112+
113+
114+
def test_dtpr005_disabled_days_arent_clickable(dash_dcc):
115+
app = dash.Dash(__name__)
116+
app.layout = html.Div(
117+
[
118+
html.Label("Operating Date"),
119+
dcc.DatePickerRange(
120+
id="dpr",
121+
min_date_allowed=datetime(2021, 1, 1),
122+
max_date_allowed=datetime(2021, 1, 31),
123+
initial_visible_month=datetime(2021, 1, 1),
124+
disabled_days=[datetime(2021, 1, 10), datetime(2021, 1, 11)],
125+
),
126+
],
127+
style={
128+
"width": "10%",
129+
"display": "inline-block",
130+
"marginLeft": 10,
131+
"marginRight": 10,
132+
"marginBottom": 10,
133+
},
134+
)
135+
dash_dcc.start_server(app)
136+
date = dash_dcc.find_element("#dpr input")
137+
assert not date.get_attribute("value")
138+
assert not any(
139+
dash_dcc.select_date_range("dpr", day_range=(10, 11))
140+
), "Disabled days should not be clickable"
141+
assert all(
142+
dash_dcc.select_date_range("dpr", day_range=(1, 2))
143+
), "Other days should be clickable"
144+
145+
# open datepicker to take snapshot
146+
date.click()
147+
dash_dcc.percy_snapshot("dtpr005 - disabled days")

tests/integration/calendar/test_date_picker_single.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,3 +140,37 @@ def test_dtps012_initial_month(dash_dcc):
140140
"#dps-initial-month .CalendarMonth.CalendarMonth_1[data-visible=true] strong",
141141
"January 2010",
142142
)
143+
144+
145+
def test_dtps013_disabled_days_arent_clickable(dash_dcc):
146+
app = dash.Dash(__name__)
147+
app.layout = html.Div(
148+
[
149+
html.Label("Operating Date"),
150+
dcc.DatePickerSingle(
151+
id="dps",
152+
min_date_allowed=datetime(2021, 1, 1),
153+
max_date_allowed=datetime(2021, 1, 31),
154+
initial_visible_month=datetime(2021, 1, 1),
155+
disabled_days=[datetime(2021, 1, 10)],
156+
),
157+
],
158+
style={
159+
"width": "10%",
160+
"display": "inline-block",
161+
"marginLeft": 10,
162+
"marginRight": 10,
163+
"marginBottom": 10,
164+
},
165+
)
166+
dash_dcc.start_server(app)
167+
date = dash_dcc.find_element("#dps input")
168+
assert not date.get_attribute("value")
169+
assert not dash_dcc.select_date_single(
170+
"dps", day=10
171+
), "Disabled days should not be clickable"
172+
assert dash_dcc.select_date_single("dps", day=1), "Other days should be clickable"
173+
174+
# open datepicker to take snapshot
175+
date.click()
176+
dash_dcc.percy_snapshot("dtps013 - disabled days")

0 commit comments

Comments
 (0)