Selected_row_ids not updating when selected_rows is changed

I have the impression there is a bug (or a feature I haven’t read about) with the behaviour of datatables.

I have a complex situation in which:

  • a first datatable A has selectable rows (single)
  • a second datatable B has selectable rows (multi)
  • a third datatable C has selectable rows (multi)

When a row is selected in A, rows are populated in B based on that choice (callback update_B_from_A)
When one or multiple rows are selected in B, rows in C are populated based on that choice (callback update_C_from_B)

I am trying to chain the callbacks to ensure that if after selections have been made, the user changes the selection in table A, all previous selections in tables B and C are removed.
I do this by setting the selected_rows in of the Output table to an empty array.

What I observed is that when I do that, the selected_rows_ids of the same tables do not get automatically updated on that basis and carry on holding the same value as before (which then causes other issues in other callbacks that depend on reading the selected_rows_ids of all 3 tables to generate some graphs.

Am I missing something? Should I set both selected_rows AND selected_rows_ids in my Outputs in the callback to ensure both are empty?

Hm, yeah that sounds like it could be a bug but it’s hard to say. any chance you could create a small reproducible example with a few lines of fake data? that’s help us diagnose the issue

The problem is still there as of July 2021 with dash-table==4.12.0 and dash==1.21.0

Here is a simple code for reproducing the problem

import dash
import dash_html_components as html
import dash_table
import pandas as pd
from dash.dependencies import Output, Input, State

df = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/solar.csv')
df['id'] = pd.Series(range(len(df)))

app = dash.Dash(__name__)

app.layout = html.Div([
    html.Button('select_all', id='btn_select_all'),
    html.Button('print_selected_indices', id='btn_print'),
    html.Div(id='output'),
    dash_table.DataTable(
        id='table',
        columns=[{"name": i, "id": i} for i in df.columns],
        data=df.to_dict('records'),
        row_selectable='multi',
    ),
])


@app.callback(
    Output('table', 'selected_rows'),
    Input('btn_select_all', 'n_clicks'),
    prevent_initial_call=True
)
def select_all(n_clicks):
    return list(range(len(df)))


@app.callback(
    Output('output', 'children'),
    Input('btn_print', 'n_clicks'),
    State('table', 'selected_row_ids'),
    State('table', 'selected_rows'),
    prevent_initial_call=True
)
def print_selected_indices(n_clicks, selected_row_ids, selected_rows):
    return f'selected_row_ids={selected_row_ids}, selected_rows={selected_rows}'


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

Run the program, click the ‘select all’ button first and then click the ‘print_selected_indices’. You will see the selected_row_ids remain while selected_rows is correct.

@victorx This is a a great MWE,

I think it looks like a bug… your example shows that if you update the selected_rows in a callback, it does not update the selected_row_ids.

A couple of interesting things:

  • If you click on the select all button, then un-select a row, then the selected_row_ids is updated correctly.

  • The derived_virtual_selected_row_ids is correct – it does get updated in the callback.

So I suppose a workaround for now is to update both the selected_rows and the selected_row_ids in a callback, or use the derived_virtual_selected_row_ids prop as the input in the callback.

The issue is still present in dash 2.6.2
Was there an issue opened on Github?

Thanks @AnnMarieW for the trick, setting the output for both “selected_rows” and “selected_row_ids” from the callback seems to work.