Skip to content

Commit 4a9f09a

Browse files
authored
Merge pull request #2867 from plotly/fix/clientside_no_output
Fix clientside no outputs
2 parents 993b57f + 0cce4c0 commit 4a9f09a

File tree

4 files changed

+59
-10
lines changed

4 files changed

+59
-10
lines changed

Diff for: CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ This project adheres to [Semantic Versioning](https://semver.org/).
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)
1212
- [#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)
13+
- [#2867](https://github.com/plotly/dash/pull/2867) Fix clientside no output callback. Fixes [#2866](https://github.com/plotly/dash/issues/2866)
1314

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

Diff for: dash/_callback.py

+2
Original file line numberDiff line numberDiff line change
@@ -549,6 +549,7 @@ def register_clientside_callback(
549549
**kwargs,
550550
):
551551
output, inputs, state, prevent_initial_call = handle_callback_args(args, kwargs)
552+
no_output = isinstance(output, (list,)) and len(output) == 0
552553
insert_callback(
553554
callback_list,
554555
callback_map,
@@ -559,6 +560,7 @@ def register_clientside_callback(
559560
state,
560561
None,
561562
prevent_initial_call,
563+
no_output=no_output,
562564
)
563565

564566
# If JS source is explicitly given, create a namespace and function

Diff for: dash/dash-renderer/src/actions/callbacks.ts

+11-9
Original file line numberDiff line numberDiff line change
@@ -278,16 +278,18 @@ async function handleClientside(
278278
returnValue = await returnValue;
279279
}
280280

281-
zipIfArray(outputs, returnValue).forEach(([outi, reti]) => {
282-
zipIfArray(outi, reti).forEach(([outij, retij]) => {
283-
const {id, property} = outij;
284-
const idStr = stringifyId(id);
285-
const dataForId = (result[idStr] = result[idStr] || {});
286-
if (retij !== dc.no_update) {
287-
dataForId[cleanOutputProp(property)] = retij;
288-
}
281+
if (outputs) {
282+
zipIfArray(outputs, returnValue).forEach(([outi, reti]) => {
283+
zipIfArray(outi, reti).forEach(([outij, retij]) => {
284+
const {id, property} = outij;
285+
const idStr = stringifyId(id);
286+
const dataForId = (result[idStr] = result[idStr] || {});
287+
if (retij !== dc.no_update) {
288+
dataForId[cleanOutputProp(property)] = retij;
289+
}
290+
});
289291
});
290-
});
292+
}
291293
} catch (e) {
292294
if (e === dc.PreventUpdate) {
293295
status = STATUS.PREVENT_UPDATE;

Diff for: tests/integration/callbacks/test_arbitrary_callbacks.py

+45-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,15 @@
11
import time
22
from multiprocessing import Value
33

4-
from dash import Dash, Input, Output, html, set_props, register_page
4+
from dash import (
5+
Dash,
6+
Input,
7+
Output,
8+
html,
9+
set_props,
10+
register_page,
11+
clientside_callback,
12+
)
513

614

715
def test_arb001_global_set_props(dash_duo):
@@ -188,3 +196,39 @@ def on_click(_):
188196
dash_duo.wait_for_style_to_equal(
189197
"#output", "background-color", "rgba(255, 0, 0, 1)"
190198
)
199+
200+
201+
def test_arb007_clientside_no_output(dash_duo):
202+
app = Dash()
203+
204+
app.layout = [
205+
html.Button("start", id="start1"),
206+
html.Button("start2", id="start2"),
207+
html.Div(id="output"),
208+
]
209+
210+
clientside_callback(
211+
"""
212+
function(_) {
213+
dash_clientside.set_props('output', {children: 'start1'})
214+
}
215+
""",
216+
Input("start1", "n_clicks"),
217+
prevent_initial_call=True,
218+
)
219+
clientside_callback(
220+
"""
221+
function(_) {
222+
dash_clientside.set_props('output', {children: 'start2'})
223+
}
224+
""",
225+
Input("start2", "n_clicks"),
226+
prevent_initial_call=True,
227+
)
228+
229+
dash_duo.start_server(app)
230+
231+
dash_duo.find_element("#start1").click()
232+
dash_duo.wait_for_text_to_equal("#output", "start1")
233+
dash_duo.find_element("#start2").click()
234+
dash_duo.wait_for_text_to_equal("#output", "start2")

0 commit comments

Comments
 (0)