Skip to content

Commit 4cd08ce

Browse files
committed
Fix bug that prevented dates from being updated externally
1 parent d05bd8d commit 4cd08ce

File tree

4 files changed

+128
-3
lines changed

4 files changed

+128
-3
lines changed

components/dash-core-components/src/fragments/DatePickerRange.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ const DatePickerRange = ({
143143
// Only end changed - send just that one
144144
setProps({end_date: dateAsStr(internalEndDate)});
145145
}
146-
}, [start_date, internalStartDate, end_date, internalEndDate, updatemode]);
146+
}, [internalStartDate, internalEndDate, updatemode]);
147147

148148
const sendStartInputAsDate = useCallback(
149149
(focusCalendar = false) => {

components/dash-core-components/src/fragments/DatePickerSingle.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ const DatePickerSingle = ({
7676
if (dateChanged) {
7777
setProps({date: dateAsStr(internalDate)});
7878
}
79-
}, [date, internalDate, setProps]);
79+
}, [internalDate]);
8080

8181
const parseUserInput = useCallback(
8282
(focusCalendar = false) => {

components/dash-core-components/tests/integration/calendar/test_date_picker_range.py

Lines changed: 69 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from datetime import datetime
2+
import time
23

3-
from dash import Dash, html, dcc
4+
from dash import Dash, Input, Output, html, dcc
45
from selenium.common.exceptions import (
56
ElementClickInterceptedException,
67
TimeoutException,
@@ -374,3 +375,70 @@ def test_dtpr008_input_click_opens_but_keeps_focus(dash_dcc):
374375
), f"Calendar should show 2026, but shows: {year_input.get_attribute('value')}"
375376

376377
assert dash_dcc.get_logs() == []
378+
379+
380+
def test_dtpr030_external_date_range_update(dash_dcc):
381+
"""Test that DatePickerRange accepts external date updates via callback without resetting."""
382+
app = Dash(__name__)
383+
app.layout = html.Div(
384+
[
385+
html.Button("Update dates", id="update-btn"),
386+
dcc.DatePickerRange(
387+
id="dpr",
388+
start_date="2024-01-01",
389+
end_date="2024-12-31",
390+
),
391+
html.Div(id="output"),
392+
]
393+
)
394+
395+
@app.callback(
396+
Output("dpr", "start_date"),
397+
Output("dpr", "end_date"),
398+
Input("update-btn", "n_clicks"),
399+
prevent_initial_call=True,
400+
)
401+
def update_dates(n_clicks):
402+
return "2021-06-01", "2021-06-30"
403+
404+
@app.callback(
405+
Output("output", "children"),
406+
Input("dpr", "start_date"),
407+
Input("dpr", "end_date"),
408+
)
409+
def display_dates(start_date, end_date):
410+
return f"Start: {start_date}, End: {end_date}"
411+
412+
dash_dcc.start_server(app)
413+
414+
# Verify initial dates
415+
dash_dcc.wait_for_text_to_equal("#output", "Start: 2024-01-01, End: 2024-12-31")
416+
start_input = dash_dcc.find_element(".dash-datepicker-start-date")
417+
end_input = dash_dcc.find_element(".dash-datepicker-end-date")
418+
assert start_input.get_attribute("value") == "2024-01-01"
419+
assert end_input.get_attribute("value") == "2024-12-31"
420+
421+
# Click button to trigger external update
422+
btn = dash_dcc.find_element("#update-btn")
423+
btn.click()
424+
425+
# Verify dates were updated and stay updated (don't reset back)
426+
dash_dcc.wait_for_text_to_equal(
427+
"#output", "Start: 2021-06-01, End: 2021-06-30", timeout=4
428+
)
429+
430+
# Give it a moment to potentially incorrectly reset
431+
time.sleep(0.5)
432+
433+
# Verify they're still the new dates
434+
assert (
435+
dash_dcc.find_element("#output").text == "Start: 2021-06-01, End: 2021-06-30"
436+
), "Dates should remain updated after external update"
437+
assert (
438+
start_input.get_attribute("value") == "2021-06-01"
439+
), "Start input should display 2021-06-01"
440+
assert (
441+
end_input.get_attribute("value") == "2021-06-30"
442+
), "End input should display 2021-06-30"
443+
444+
assert dash_dcc.get_logs() == []

components/dash-core-components/tests/integration/calendar/test_date_picker_single.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -619,3 +619,60 @@ def test_dtps026_input_click_opens_but_keeps_focus(dash_dcc):
619619
), f"Calendar should show 2026, but shows: {year_input.get_attribute('value')}"
620620

621621
assert dash_dcc.get_logs() == []
622+
623+
624+
def test_dtps030_external_date_update(dash_dcc):
625+
"""Test that DatePickerSingle accepts external date updates via callback without resetting."""
626+
app = Dash(__name__)
627+
app.layout = html.Div(
628+
[
629+
html.Button("Update to 2021-06-23", id="update-btn"),
630+
dcc.DatePickerSingle(
631+
id="dps",
632+
date="2024-11-25",
633+
),
634+
html.Div(id="output"),
635+
]
636+
)
637+
638+
@app.callback(
639+
Output("dps", "date"),
640+
Input("update-btn", "n_clicks"),
641+
prevent_initial_call=True,
642+
)
643+
def update_date(n_clicks):
644+
return "2021-06-23"
645+
646+
@app.callback(
647+
Output("output", "children"),
648+
Input("dps", "date"),
649+
)
650+
def display_date(date):
651+
return f"Date: {date}"
652+
653+
dash_dcc.start_server(app)
654+
655+
# Verify initial date
656+
dash_dcc.wait_for_text_to_equal("#output", "Date: 2024-11-25")
657+
input_element = dash_dcc.find_element(".dash-datepicker-input")
658+
assert input_element.get_attribute("value") == "2024-11-25"
659+
660+
# Click button to trigger external update
661+
btn = dash_dcc.find_element("#update-btn")
662+
btn.click()
663+
664+
# Verify date was updated and stays updated (doesn't reset back)
665+
dash_dcc.wait_for_text_to_equal("#output", "Date: 2021-06-23", timeout=4)
666+
667+
# Give it a moment to potentially incorrectly reset
668+
time.sleep(0.5)
669+
670+
# Verify it's still the new date
671+
assert (
672+
dash_dcc.find_element("#output").text == "Date: 2021-06-23"
673+
), "Date should remain 2021-06-23 after external update"
674+
assert (
675+
input_element.get_attribute("value") == "2021-06-23"
676+
), "Input should display 2021-06-23"
677+
678+
assert dash_dcc.get_logs() == []

0 commit comments

Comments
 (0)