Skip to content

Commit 993b57f

Browse files
authored
Merge pull request #2856 from plotly/fix/multi-set-props
Fix/multi set props
2 parents 2d21e62 + 72707ad commit 993b57f

File tree

6 files changed

+40
-1
lines changed

6 files changed

+40
-1
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ This project adheres to [Semantic Versioning](https://semver.org/).
99
- [#2860](https://github.com/plotly/dash/pull/2860) Fix dcc.Loading to apply overlay_style only to the children and not the spinner. Fixes [#2858](https://github.com/plotly/dash/issues/2858)
1010
- [#2854](https://github.com/plotly/dash/pull/2854) Fix dcc.Dropdown resetting empty values to null and triggering callbacks. Fixes [#2850](https://github.com/plotly/dash/issues/2850)
1111
- [#2859](https://github.com/plotly/dash/pull/2859) Fix base patch operators. fixes [#2855](https://github.com/plotly/dash/issues/2855)
12+
- [#2856](https://github.com/plotly/dash/pull/2856) Fix multiple consecutive calls with same id to set_props only keeping the last props. Fixes [#2852](https://github.com/plotly/dash/issues/2852)
1213

1314
## [2.17.0] - 2024-05-03
1415

dash/_callback_context.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,11 @@ def timing_information(self):
252252
def set_props(self, component_id: typing.Union[str, dict], props: dict):
253253
ctx_value = _get_context_value()
254254
_id = stringify_id(component_id)
255-
ctx_value.updated_props[_id] = props
255+
existing = ctx_value.updated_props.get(_id)
256+
if existing is not None:
257+
ctx_value.updated_props[_id] = {**existing, **props}
258+
else:
259+
ctx_value.updated_props[_id] = props
256260

257261

258262
callback_context = CallbackContext()

dash/long_callback/_proxy_set_props.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@ class ProxySetProps(dict):
77
def __init__(self, on_change):
88
super().__init__()
99
self.on_change = on_change
10+
self._data = {}
1011

1112
def __setitem__(self, key, value):
1213
self.on_change(key, value)
14+
self._data.setdefault(key, {})
15+
self._data[key] = {**self._data[key], **value}
16+
17+
def get(self, key):
18+
return self._data.get(key)

tests/integration/callbacks/test_arbitrary_callbacks.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,3 +165,26 @@ def on_click(clicked):
165165
".dash-fe-error__title",
166166
"Callback error with no output from input start.n_clicks",
167167
)
168+
169+
170+
def test_arb006_multi_set_props(dash_duo):
171+
app = Dash()
172+
173+
app.layout = [
174+
html.Button("start", id="start"),
175+
html.Div("initial", id="output"),
176+
]
177+
178+
@app.callback(
179+
Input("start", "n_clicks"),
180+
)
181+
def on_click(_):
182+
set_props("output", {"children": "changed"})
183+
set_props("output", {"style": {"background": "rgb(255,0,0)"}})
184+
185+
dash_duo.start_server(app)
186+
dash_duo.wait_for_element("#start").click()
187+
dash_duo.wait_for_text_to_equal("#output", "changed")
188+
dash_duo.wait_for_style_to_equal(
189+
"#output", "background-color", "rgba(255, 0, 0, 1)"
190+
)

tests/integration/long_callback/app_arbitrary.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,11 @@
2525
Input("start", "n_clicks"),
2626
prevent_initial_call=True,
2727
background=True,
28+
interval=500,
2829
)
2930
def on_click(_):
3031
set_props("secondary", {"children": "first"})
32+
set_props("secondary", {"style": {"background": "red"}})
3133
time.sleep(2)
3234
set_props("secondary", {"children": "second"})
3335
return "completed"

tests/integration/long_callback/test_basic_long_callback017.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ def test_lcbc017_long_callback_set_props(dash_duo, manager):
88
dash_duo.find_element("#start").click()
99

1010
dash_duo.wait_for_text_to_equal("#secondary", "first")
11+
dash_duo.wait_for_style_to_equal(
12+
"#secondary", "background-color", "rgba(255, 0, 0, 1)"
13+
)
1114
dash_duo.wait_for_text_to_equal("#output", "initial")
1215
dash_duo.wait_for_text_to_equal("#secondary", "second")
1316
dash_duo.wait_for_text_to_equal("#output", "completed")

0 commit comments

Comments
 (0)