Updating dropdown options so that value no longer in options doesn't fire callbacks watching value

[Apologies for the “not so minimal” minimal example, it’s the best I could figure out…]

I’ve also filed an Issue #819 for this.

I have a callback that watches the value of a Dropdown (aka the “details” Dropdown) and outputs a set of divs into a “details div” based on that value.

The set of options for that Dropdown are drawn dynamically from a list (e.g. “jobs”). There’s a callback that watches jobs.data and updates the options.

There’s another Dropdown and button that allow for jobs to be deleted from jobs.data .

When the job that is currently selected for detailed display (visible in the Dropdown and detail Div) is deleted, the set options for the “details” Dropdown is updated and the value is removed from the Dropdown’s visual display.

BUT the “details” Dropdown value is not updated so the callback that is watching that value never fires and “details display” does not get updated.

I can work around this by having callback that’s watching the “details” Dropdown’s value also watch its set of options and clear the display when the value is not in the options.

Given that the selected value is cleared from the GUI when it is no longer in options, I expected that the value would be cleared and that callbacks watching the value would fire.

There’s a full demo in this gist. You can exercise the behavior by dragging files into the upload box, selecting on to display, the deleting that same file. The Details section does not change. You can workaround the issue by uncommenting the lines labeled # FIXES_IT.

Here’s the callback that updates the Display div:

@app.callback(
    Output("current-job-details", "children"),
    # FIXES_IT [Input("current-job", "value"), Input("current-job", "options"),],
    [Input("current-job", "value"), Input("current-job", "options"),],
    [State("current-job-details", "children")],
)
# FIXES_IT def display_current_job(job_id, options, divs):
def display_current_job(job_id, options, divs):
    print(f"DISPLAY: {job_id} -> {options}")
    # There's nothing to do.
    if job_id is None and divs is None:
        raise PreventUpdate

    # There's no current selection but there's something being
    # displayed, so clear the display.
    if job_id is None:
        return []

    # FIXES_IT if all([job_id != o["value"] for o in options]):
    # FIXES_IT    return []

    divs = []
    divs.append(html.Div(children=[f"Detailed explanation of {job_id}"]))

    return divs