Skip to content

Commit 441a9ac

Browse files
authored
Merge branch 'dev' into connection-status
2 parents 7e84ccf + 7043c13 commit 441a9ac

File tree

4 files changed

+391
-3
lines changed

4 files changed

+391
-3
lines changed

CHANGELOG.md

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

55
## [UNRELEASED]
6+
### Added
7+
- [#1240](https://github.com/plotly/dash/pull/1240) Adds `callback_context` to clientside callbacks (e.g. `dash_clientside.callback_context.triggered`). Supports `triggered`, `inputs`, `inputs_list`, `states`, and `states_list`, all of which closely resemble their serverside cousins.
8+
69
### Changed
710
- [#1237](https://github.com/plotly/dash/pull/1237) Closes [#920](https://github.com/plotly/dash/issues/920): Converts hot reload fetch failures into a server status indicator showing whether the latest fetch succeeded or failed. Callback fetch failures still appear as errors but have a clearer message.
811

dash-renderer/src/actions/index.js

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -533,6 +533,35 @@ const getVals = input =>
533533

534534
const zipIfArray = (a, b) => (Array.isArray(a) ? zip(a, b) : [[a, b]]);
535535

536+
function inputsToDict(inputs_list) {
537+
// Ported directly from _utils.py, inputs_to_dict
538+
// takes an array of inputs (some inputs may be an array)
539+
// returns an Object (map):
540+
// keys of the form `id.property` or `{"id": 0}.property`
541+
// values contain the property value
542+
if (!inputs_list) {
543+
return {};
544+
}
545+
const inputs = {};
546+
for (let i = 0; i < inputs_list.length; i++) {
547+
if (Array.isArray(inputs_list[i])) {
548+
const inputsi = inputs_list[i];
549+
for (let ii = 0; ii < inputsi.length; ii++) {
550+
const id_str = `${stringifyId(inputsi[ii].id)}.${
551+
inputsi[ii].property
552+
}`;
553+
inputs[id_str] = inputsi[ii].value ?? null;
554+
}
555+
} else {
556+
const id_str = `${stringifyId(inputs_list[i].id)}.${
557+
inputs_list[i].property
558+
}`;
559+
inputs[id_str] = inputs_list[i].value ?? null;
560+
}
561+
}
562+
return inputs;
563+
}
564+
536565
function handleClientside(clientside_function, payload) {
537566
const dc = (window.dash_clientside = window.dash_clientside || {});
538567
if (!dc.no_update) {
@@ -552,12 +581,26 @@ function handleClientside(clientside_function, payload) {
552581
let returnValue;
553582

554583
try {
584+
// setup callback context
585+
const input_dict = inputsToDict(inputs);
586+
dc.callback_context = {};
587+
dc.callback_context.triggered = payload.changedPropIds.map(prop_id => ({
588+
prop_id: prop_id,
589+
value: input_dict[prop_id],
590+
}));
591+
dc.callback_context.inputs_list = inputs;
592+
dc.callback_context.inputs = input_dict;
593+
dc.callback_context.states_list = state;
594+
dc.callback_context.states = inputsToDict(state);
595+
555596
const {namespace, function_name} = clientside_function;
556597
let args = inputs.map(getVals);
557598
if (state) {
558599
args = concat(args, state.map(getVals));
559600
}
560601
returnValue = dc[namespace][function_name](...args);
602+
603+
delete dc.callback_context;
561604
} catch (e) {
562605
if (e === dc.PreventUpdate) {
563606
return {};

tests/integration/clientside/assets/clientside.js

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,30 @@ window.dash_clientside.clientside = {
5656
resolve('foo');
5757
}, 1);
5858
});
59-
}
59+
},
6060

61-
}
61+
triggered_to_str: function(n_clicks0, n_clicks1) {
62+
const triggered = dash_clientside.callback_context.triggered;
63+
return triggered.map(t => `${t.prop_id} = ${t.value}`).join(', ');
64+
},
65+
66+
inputs_to_str: function(n_clicks0, n_clicks1) {
67+
const inputs = dash_clientside.callback_context.inputs;
68+
const keys = Object.keys(inputs);
69+
return keys.map(k => `${k} = ${inputs[k]}`).join(', ');
70+
},
71+
72+
inputs_list_to_str: function(n_clicks0, n_clicks1) {
73+
return JSON.stringify(dash_clientside.callback_context.inputs_list);
74+
},
75+
76+
states_to_str: function(val0, val1, st0, st1) {
77+
const states = dash_clientside.callback_context.states;
78+
const keys = Object.keys(states);
79+
return keys.map(k => `${k} = ${states[k]}`).join(', ');
80+
},
81+
82+
states_list_to_str: function(val0, val1, st0, st1) {
83+
return JSON.stringify(dash_clientside.callback_context.states_list);
84+
}
85+
};

0 commit comments

Comments
 (0)