Stateful representation using pattern matching callbacks

Thought I would share a use case I’ve found for pattern matching callbacks: 📣 Dash v1.11.0 Release - Introducing Pattern-Matching Callbacks

I’m building some complex single page applications, and part of the UI dev is incorporating a state so that user interactions can be carried across different parts of the app, which I call “modules”.

This could, and was done before, but introducting pattern matching has made the process much less cumbersome as well as less prone to errors.

import json

import dash
from dash.dependencies import Input, Output, State, ALL
import dash_core_components as dcc
import dash_html_components as html

ctx = dash.callback_context

app = dash.Dash(__name__)

app.layout = html.Div(
    [
        dcc.Store(id='state', data={}),
        # module a
        html.Div(
            [
                html.P('Module A'),
                dcc.Dropdown(
                    id={'module': 'module_a', 'id': 'dropdown_1'},
                    options=[{'label': i, 'value': i} for i in range(10)],
                    value=0,
                ),
                dcc.Dropdown(
                    id={'module': 'module_a', 'id': 'dropdown_2'},
                    options=[{'label': i, 'value': i} for i in range(10)],
                    value=0,
                ),
            ]
        ),
        # module b
        html.Div(
            [
                html.P('Module B'),
                dcc.Dropdown(
                    id={'module': 'module_b', 'id': 'dropdown_1'},
                    options=[{'label': i, 'value': i} for i in range(10)],
                    value=0,
                ),
                dcc.Dropdown(
                    id={'module': 'module_b', 'id': 'dropdown_2'},
                    options=[{'label': i, 'value': i} for i in range(10)],
                    value=0,
                ),
            ]
        ),
        # Inspection
        html.Div([html.Pre(id='state_inspector')]),
    ]
)


@app.callback(
    Output('state', 'data'),
    [
        Input({'module': 'module_a', 'id': ALL}, 'value'),
        Input({'module': 'module_b', 'id': ALL}, 'value'),
    ],
)
def store_state(*args):

    # unpack inputs list
    mod_a, mod_b = ctx.inputs_list
    return {
        'module_a': {c['id']['id']: c['value'] for c in mod_a},
        'module_b': {c['id']['id']: c['value'] for c in mod_b},
    }


@app.callback(Output('state_inspector', 'children'), [Input('state', 'data')])
def display_state(state):
    return json.dumps(state, indent=2)


if __name__ == '__main__':
    app.run_server(debug=True)

3 Likes