Skip to content

Commit 71b1e6f

Browse files
authored
Merge pull request #2881 from insistence/insistence-dev
Add outputs_list to window.dash_clientside.callback_context
2 parents 553db47 + f7fed34 commit 71b1e6f

File tree

3 files changed

+137
-0
lines changed

3 files changed

+137
-0
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@
22
All notable changes to `dash` will be documented in this file.
33
This project adheres to [Semantic Versioning](https://semver.org/).
44

5+
## [UNRELEASED]
6+
7+
## Added
8+
9+
- [#2881](https://github.com/plotly/dash/pull/2881) Add outputs_list to window.dash_clientside.callback_context. Fixes [#2877](https://github.com/plotly/dash/issues/2877).
10+
511
## [2.17.1] - 2024-06-12
612

713
## Fixed

dash/dash-renderer/src/actions/callbacks.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,7 @@ async function handleClientside(
272272
dc.callback_context.inputs = inputDict;
273273
dc.callback_context.states_list = state;
274274
dc.callback_context.states = stateDict;
275+
dc.callback_context.outputs_list = outputs;
275276

276277
let returnValue = dc[namespace][function_name](...args);
277278

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
from dash import (
2+
Dash,
3+
Input,
4+
Output,
5+
html,
6+
clientside_callback,
7+
)
8+
9+
10+
def test_clol001_clientside_outputs_list_by_single_output(dash_duo):
11+
app = Dash(__name__)
12+
app.layout = html.Div(
13+
[html.Button("trigger", id="trigger-demo"), html.Pre(id="output-demo")],
14+
style={"padding": 50},
15+
)
16+
17+
clientside_callback(
18+
"""(n_clicks) => {
19+
return JSON.stringify(window.dash_clientside.callback_context.outputs_list);
20+
}""",
21+
Output("output-demo", "children"),
22+
Input("trigger-demo", "n_clicks"),
23+
prevent_initial_call=True,
24+
)
25+
26+
dash_duo.start_server(app)
27+
28+
trigger_clicker = dash_duo.wait_for_element("#trigger-demo")
29+
trigger_clicker.click()
30+
dash_duo.wait_for_text_to_equal(
31+
"#output-demo",
32+
'{"id":"output-demo","property":"children"}',
33+
)
34+
35+
36+
def test_clol002_clientside_outputs_list_by_multiple_output1(dash_duo):
37+
app = Dash(__name__)
38+
app.layout = html.Div(
39+
[
40+
html.Button("trigger", id="trigger-demo"),
41+
html.Pre(id="output-demo1"),
42+
html.Pre(id="output-demo2"),
43+
],
44+
style={"padding": 50},
45+
)
46+
47+
clientside_callback(
48+
"""(n_clicks) => {
49+
return [JSON.stringify(window.dash_clientside.callback_context.outputs_list), JSON.stringify(window.dash_clientside.callback_context.outputs_list)];
50+
}""",
51+
[Output("output-demo1", "children"), Output("output-demo2", "children")],
52+
Input("trigger-demo", "n_clicks"),
53+
prevent_initial_call=True,
54+
)
55+
56+
dash_duo.start_server(app)
57+
58+
dash_duo.find_element("#trigger-demo").click()
59+
dash_duo.wait_for_text_to_equal(
60+
"#output-demo1",
61+
'[{"id":"output-demo1","property":"children"},{"id":"output-demo2","property":"children"}]',
62+
)
63+
dash_duo.wait_for_text_to_equal(
64+
"#output-demo2",
65+
'[{"id":"output-demo1","property":"children"},{"id":"output-demo2","property":"children"}]',
66+
)
67+
68+
69+
def test_clol003_clientside_outputs_list_by_multiple_output2(dash_duo):
70+
app = Dash(__name__)
71+
app.layout = html.Div(
72+
[
73+
html.Button("trigger1", id="trigger-demo1"),
74+
html.Button("trigger2", id="trigger-demo2"),
75+
html.Pre(id="output-demo1"),
76+
html.Pre(id="output-demo2"),
77+
],
78+
style={"padding": 50},
79+
)
80+
81+
clientside_callback(
82+
"""(n_clicks1, n_clicks2) => {
83+
if (window.dash_clientside.callback_context.triggered_id === 'trigger-demo1') {
84+
return [JSON.stringify(window.dash_clientside.callback_context.outputs_list), window.dash_clientside.no_update];
85+
} else if (window.dash_clientside.callback_context.triggered_id === 'trigger-demo2') {
86+
return [window.dash_clientside.no_update, JSON.stringify(window.dash_clientside.callback_context.outputs_list)];
87+
}
88+
return [window.dash_clientside.no_update, window.dash_clientside.no_update];
89+
}""",
90+
[Output("output-demo1", "children"), Output("output-demo2", "children")],
91+
[Input("trigger-demo1", "n_clicks"), Input("trigger-demo2", "n_clicks")],
92+
prevent_initial_call=True,
93+
)
94+
95+
dash_duo.start_server(app)
96+
97+
dash_duo.find_element("#trigger-demo1").click()
98+
dash_duo.wait_for_text_to_equal(
99+
"#output-demo1",
100+
'[{"id":"output-demo1","property":"children"},{"id":"output-demo2","property":"children"}]',
101+
)
102+
dash_duo.find_element("#trigger-demo2").click()
103+
dash_duo.wait_for_text_to_equal(
104+
"#output-demo2",
105+
'[{"id":"output-demo1","property":"children"},{"id":"output-demo2","property":"children"}]',
106+
)
107+
108+
109+
def test_clol004_clientside_outputs_list_by_no_output(dash_duo):
110+
app = Dash(__name__)
111+
app.layout = html.Div(
112+
[html.Button("trigger", id="trigger-demo"), html.Pre(id="output-demo")],
113+
style={"padding": 50},
114+
)
115+
116+
clientside_callback(
117+
"""(n_clicks) => {
118+
window.dash_clientside.set_props('output-demo', {'children': JSON.stringify(window.dash_clientside.callback_context.outputs_list)});
119+
}""",
120+
Input("trigger-demo", "n_clicks"),
121+
prevent_initial_call=True,
122+
)
123+
124+
dash_duo.start_server(app)
125+
126+
dash_duo.find_element("#trigger-demo").click()
127+
dash_duo.wait_for_text_to_equal(
128+
"#output-demo",
129+
"",
130+
)

0 commit comments

Comments
 (0)