Want to update dropdown options, but not selected value

I’m creating an app where I want to poll a database every 10 seconds to see if new records are available and dynamically update a dropdown. However, the way I have it set up now, the callback updates the options value AND resets the value the user has chosen:

@app.callback(Output('reflapmenu', 'options'),
              [Input('leaderboard-interval', 'n_intervals')])
def build_session_dropdown(notused):

    #placing connection inside to avoid having stale connection
    conn = <database connection omitted>

    df = pd.read_sql("""select
                        sessionuid,
                        lapnumber,
                        laptime,
                        playercarindex
                        from v_leaderboard_melbourne
                        where laptime >= 60
                        order by laptime
                        limit 50
                    """, conn)

    #formatting for session column to make table width smaller
    df["session"] = [f"""S{x[-4:]}""" for x in df["sessionuid"]]

    options = [{'label': f"""{uid} - Lap {lnum} - {lapt}""", 'value': uid} for uid, lnum, lapt in
                zip(df["session"], df["lapnumber"], df["laptime"])]

    return options

#### reference lap: build list dynamically
reflapmenu = dcc.Dropdown(
    id='reflapmenu',
    searchable=False,
    clearable=False,
    style=dict(width = '275px')
)

As it stands now, on page load the dropdown does not have a value chosen (the dropdown shows blank, waiting for the user to choose). The user can then choose a value, but when the callback fires, it updates the options argument and resets the state of the value to blank…I would like only the options field to update (i.e. give the user more choices when they become available), but don’t change their current selection.

Is this possible? Do I have to stash their current choice somehow?

You could take the current value of the dropdown as a State, and use the new multiple output feature (make sure you have Dash version 0.39.0 or later) to set both the dropdown options and the value.

Here’s a simple version of that that doesn’t use any of the SQL logic, but it should hopefully be pretty clear how to adapt it to your situation

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

app = dash.Dash()

app.layout = html.Div(
    [
        dcc.Interval(id="interval", interval=10000),
        dcc.Checklist(
            id="checklist",
            options=[
                {"label": "value 1", "value": 1},
                {"label": "value 2", "value": 2},
                {"label": "value 3", "value": 3},
            ],
            values=[1],
        ),
        dcc.Dropdown(id="dropdown"),
    ]
)


@app.callback(
    [Output("dropdown", "options"), Output("dropdown", "value")],
    [Input("interval", "n_intervals")],
    [State("dropdown", "value"), State("checklist", "values")]
)
def make_dropdown_options(n, value, values):
    options = [{"label": f"Option {v}", "value": v} for v in values]

    if value not in [o["value"] for o in options]:
        # if the value is not in the new options list, we choose a different value
        if options:
            value = options[0]["value"]
        else:
            value = None

    return options, value


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

I use the checklist to decide which options should be rendered, then every 10 seconds it checks the state of the checklist and updates the options accordingly, and you can see that the selected value in the dropdown is preserved.

2 Likes

Thanks for responding, unfortunately I’m a bit confused. (I did upgrade Dash to 0.39, thanks for the tip.)

For your callback code and below, is the code reading the state from dropdown and checklist first, passing that through the make_dropdown_options function, then on output just setting the options and value fields for dropdown? If so, do I need to pass the state of all objects through all callbacks?

For your callback code and below, is the code reading the state from dropdown and checklist first, passing that through the make_dropdown_options function, then on output just setting the options and value fields for dropdown ?

Yep, pretty much. State behaves basically the same as Input, except that it doesn’t trigger the callback. So you can use the value of the dropdown in your callback function, without the callback getting triggered when the dropdown value changes.

If so, do I need to pass the state of all objects through all callbacks?

Nope, just anything whose current value would be useful to you inside the callback.

1 Like