AG Grid Row Selection and Display Issues

Hi everybody!
I’ve been making a series of AG grids that respond to selections in other AG grids. As in, when a row is selected in the control grid, a corresponding row shows up in another grid. However, I’ve been having issues with the second part of that functionality. When I select more than 2 rows in the control grid, the newly selected rows do not show up in the second grid. The newly selected rows only show up if I uncheck one of the first two selected rows, and even then, only 2 rows show up, even if I had selected 5 rows in the control grid. Here is an isolated example of what I’m working with:

from flask import Flask
import sys
print(sys.version)

from dash import Dash, html, dcc, dash_table, Output, Input, State, callback_context
import pandas as pd
import dash_ag_grid as dag
import plotly.express as px
import dash_daq as daq
import plotly.graph_objects as go
import dash_bootstrap_components as dbc
import numpy as np
#from collections import OrderedDict

from data import get_control_column_defs, get_control_row_data, get_peaks_row_data, get_peaks_column_defs

@app.callback(
    [Output('peaks-summary-grid', 'filterModel'),
     Output('peaks-summary-grid', 'style')],
    Input('my-grid', 'selectedRows'),
    State('peaks-summary-grid', 'filterModel')
)
def update_filter_model_and_visibility(selected_rows, current_filter_model):
    if not selected_rows:
        return {}, {'display': 'none'}

    conditions = []
    for row in selected_rows:
        conditions.append({
            'filterType': 'number',
            'type': 'equals',
            'filter': row['internal-id']
        })

    new_filter_model = {
        'internal-id': {
            'filterType': 'number',
            'operator': 'OR',
            'conditions': conditions
        }
    }

    return new_filter_model, {'display': 'block'}

app.layout = dbc.Container([
                    dag.AgGrid(
                    #CONTROL GRID
                        id="my-grid",  # use this id for update callbacks
                        columnDefs=get_control_column_defs(),
                        rowData=get_control_row_data(),
                        defaultColDef={"filter": True},
                        dashGridOptions={
                            "rowSelection": "multiple",
                            'suppressRowClickSelection': True,
                            'suppressMovableColumns': True,
                            'overflow':'scroll',
                            #'alwaysShowVerticalScroll':True,
                            "domLayout": "autoHeight",
                            'height':'200px'
                        },
                    ),
                    dag.AgGrid(
                        #SECONDARY GRID
                        columnDefs=get_peaks_column_defs(),
                        rowData=get_peaks_row_data(),
                        defaultColDef=get_peaks_default_col_defs(),
                        dashGridOptions={#"animateRows": False,
                        "domLayout": "autoHeight",
                        'overflow':'scroll',
                        'height' : '200px'
                        },
                        id="peaks-summary-grid",
                        filterModel={},
                        #getRowStyle = getRowStyle,
                        style={'display': 'none','overflow':'scroll'}  # starts off hidden, appears when rows are checked
], #closes container
fluid=True,
style={'display':'flex'},
className='full-container')

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

Hi @peachy_oasis and welcome to the Dash community :peach: :palm_tree:

It’s hard to tell what’s causing the problem without being able to run the example. Could you please provide a complete minimal example with some sample data that duplicates the problem?

Hi! Thank you for replying. This example should be able to run.

from flask import Flask
import sys
print(sys.version)

from dash import Dash, html, dcc, dash_table, Output, Input, State, callback_context
import pandas as pd
import dash_ag_grid as dag
import plotly.express as px
import dash_daq as daq
import plotly.graph_objects as go
import dash_bootstrap_components as dbc
import numpy as np

#Data for grids
def get_control_column_defs():
    column_defs = [
    {'headerName':'internal-id','field':'internal-id','hide':True},
    {'headerName': "ID", 'field': 'id', 'sortable': True, 'filter': True,
    "checkboxSelection": True, "headerCheckboxSelection": True,},
    {'headerName': "Run", 'field': 'run', 'sortable': True, 'filter': True},
    {'headerName': "Title", 'field': 'title', 'sortable': True, 'filter': True},
    {'headerName': "Measurement Type", 'field': 'measurement', 'sortable': True, 'filter': True},
    ]
    return column_defs

def get_control_row_data():
    row_data = [ #data that fills in AG grid
    {'db-id':1,"internal-id":1,"id": 1, 'run': '1','title': "Default", "measurement": "Normal",},
    {'db-id':2,"internal-id":2,"id": 1, 'run': '1','title': "Sand & Silt", "measurement": "Normal",},
    {'db-id':2,"internal-id":3,"id": 2,'run': '2','title': "Sand & Silt", "measurement": "Normal",},
    {'db-id':2,"internal-id":4,"id": 3, 'run':'3','title': "Sand & Silt", "measurement": "Normal",},
    {'db-id':2,"internal-id":5,"id": 4,"run": 'Avg','title': "Sand & Silt", "measurement": "Average",},
    {'db-id':2,"internal-id":6,"id": 5,"run": '1','title': "Sand & Silt", "measurement": "Normal",},
    {'db-id':2,"internal-id":7,"id": 6,"run": '2','title': "Sand & Silt", "measurement": "Normal",},
    {'db-id':2,"internal-id":8,"id": 7,"run": '3','title': "Sand & Silt", "measurement": "Normal",},
    {'db-id':2,"internal-id":9,"id": 8,"run": 'Avg','title': "Sand & Silt", "measurement": "Average",},
    {'db-id':2,"internal-id":10,"id": 9,"run": '1','title': "Sand & Silt", "measurement": "Normal",},
    {'db-id':2,"internal-id":11,"id": 10,"run": '2','title': "Sand & Silt", "measurement": "Normal",},
    {'db-id':2,"internal-id":12,"id": 11,"run": '3','title': "Sand & Silt", "measurement": "Normal",},
    {'db-id':2,"internal-id":13,"id": 12,"run": 'Avg','title': "Sand & Silt", "measurement": "Average",},
     ]
    return row_data

def get_peaks_column_defs():

    columnDefs=[
    {'headerName':'Number', 'field' : 'internal-id', 'hide':False, 'filter': 'agNumberColumnFilter',
    'cellStyle':{
            # Set of color rules
            "styleConditions": [
                {
                    "condition": "[1].includes(params.value)",
                    "style": {"backgroundColor": "DeepSkyBlue", 'color':'white'},
                },{
                    "condition": "[2].includes(params.value)",
                    "style": {"backgroundColor": "Maroon", 'color':'white'},
                },{
                    "condition": "[3].includes(params.value)",
                    "style": {"backgroundColor": "Coral", 'color':'white'},
                },{
                    "condition": "[4].includes(params.value)",
                    "style": {"backgroundColor": "MediumPurple", 'color':'white'},
                },{
                    "condition": "[5].includes(params.value)",
                    "style": {"backgroundColor": "LimeGreen", 'color':'white'},
                },{
                    "condition": "[6].includes(params.value)",
                    "style": {"backgroundColor": "DarkSlateBlue", 'color':'white'},
                },{
                    "condition": "[7].includes(params.value)",
                    "style": {"backgroundColor": "Purple", 'color':'white'},
                },{
                    "condition": "[8].includes(params.value)",
                    "style": {"backgroundColor": "Gold", 'color':'white'},
                },{
                    "condition": "[9].includes(params.value)",
                    "style": {"backgroundColor": "DarkTurquoise", 'color':'white'},
                },{
                    "condition": "[10].includes(params.value)",
                    "style": {"backgroundColor": "DarkBlue", 'color':'white'},
                },{
                    "condition": "[11].includes(params.value)",
                    "style": {"backgroundColor": "HotPink", 'color':'white'},
                },{
                    "condition": "[12].includes(params.value)",
                    "style": {"backgroundColor": "Indigo", 'color':'white'},
                },
            ],
            # Default style if no rules apply
            "defaultStyle": {"backgroundColor": "mediumaquamarine"},
        }},
    {'headerName':'Sample', 'field':'sample','sortable':True,'filter':True},
    ]
    return columnDefs

def get_peaks_row_data():
    rowData=[{'internal-id':1,'sample':'1-1#1},
        {'internal-id':2,'sample':'2-2#2'},
        {'internal-id':3,'sample':'2-2#2'},
        {'internal-id':4,'sample':'2-2#2’},
        {'internal-id':5,'sample':'2-2#2'},
        {'internal-id':6,'sample':'2-2#2'},
        {'internal-id':7,'sample':'2-2#2'},
        {'internal-id':8,'sample':'2-2#2'},
        {'internal-id':9,'sample':'2-2#2'},
        {'internal-id':10,'sample':'2-2#2'},
        {'internal-id':11,'sample':'2-2#2'},
        {'internal-id':12,'sample':'2-2#2'},
        {'internal-id':13,'sample':'2-2#2'},]
    return rowData

def get_peaks_default_col_defs():
    defaultColDef = {
    "flex": 1,
    "minWidth": 150,
    "filter": "agTextColumnFilter",}
    return defaultColDef

@app.callback(
    [Output('peaks-summary-grid', 'filterModel'),
     Output('peaks-summary-grid', 'style')],
    Input('my-grid', 'selectedRows'),
    State('peaks-summary-grid', 'filterModel')
)
def update_filter_model_and_visibility(selected_rows, current_filter_model):
    if not selected_rows:
        return {}, {'display': 'none'}

    conditions = []
    for row in selected_rows:
        conditions.append({
            'filterType': 'number',
            'type': 'equals',
            'filter': row['internal-id']
        })

    new_filter_model = {
        'internal-id': {
            'filterType': 'number',
            'operator': 'OR',
            'conditions': conditions
        }
    }

    return new_filter_model, {'display': 'block'}

app.layout = dbc.Container([
                    dag.AgGrid(
                    #CONTROL GRID
                        id="my-grid",  # use this id for update callbacks
                        columnDefs=get_control_column_defs(),
                        rowData=get_control_row_data(),
                        defaultColDef={"filter": True},
                        dashGridOptions={
                            "rowSelection": "multiple",
                            'suppressRowClickSelection': True,
                            'suppressMovableColumns': True,
                            'overflow':'scroll',
                            #'alwaysShowVerticalScroll':True,
                            "domLayout": "autoHeight",
                            'height':'200px'
                        },
                    ),
                    dag.AgGrid(
                        #SECONDARY GRID
                        columnDefs=get_peaks_column_defs(),
                        rowData=get_peaks_row_data(),
                        defaultColDef=get_peaks_default_col_defs(),
                        dashGridOptions={#"animateRows": False,
                        "domLayout": "autoHeight",
                        'overflow':'scroll',
                        'height' : '200px'
                        },
                        id="peaks-summary-grid",
                        filterModel={},
                        style={'display': 'none','overflow':'scroll'}  # starts off hidden, appears when rows are checked
], #closes container
fluid=True,
style={'display':'flex'},
className='full-container')

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

I tried copying the example you just posted and it doesn’t run

Apologies. This one runs on my machine and reproduces the bug.

from flask import Flask
import sys
print(sys.version)

from dash import Dash, html, dcc, dash_table, Output, Input, State, callback_context
import pandas as pd
import dash_ag_grid as dag
import plotly.express as px
import dash_daq as daq
import plotly.graph_objects as go
import dash_bootstrap_components as dbc
import numpy as np

server = Flask(__name__)

app = Dash(__name__, external_stylesheets=[dbc.themes.FLATLY],server=server, routes_pathname_prefix='/dash/')
app.title = "Dimensions LS Emulator"

@server.route('/')
def hello_world():
    return 'Welcome to the index page. There is nothing to see here. Try /dash/.'

#Data for grids
def get_control_column_defs():
    column_defs = [
    {'headerName':'internal-id','field':'internal-id','hide':True},
    {'headerName': "ID", 'field': 'id', 'sortable': True, 'filter': True,
    "checkboxSelection": True, "headerCheckboxSelection": True,},
    {'headerName': "Run", 'field': 'run', 'sortable': True, 'filter': True},
    {'headerName': "Title", 'field': 'title', 'sortable': True, 'filter': True},
    {'headerName': "Measurement Type", 'field': 'measurement', 'sortable': True, 'filter': True},
    ]
    return column_defs

def get_control_row_data():
    row_data = [ #data that fills in AG grid
    {'db-id':1,"internal-id":1,"id": 1, 'run': '1','title': "Default", "measurement": "Normal",},
    {'db-id':2,"internal-id":2,"id": 1, 'run': '1','title': "Sand & Silt", "measurement": "Normal",},
    {'db-id':2,"internal-id":3,"id": 2,'run': '2','title': "Sand & Silt", "measurement": "Normal",},
    {'db-id':2,"internal-id":4,"id": 3, 'run':'3','title': "Sand & Silt", "measurement": "Normal",},
    {'db-id':2,"internal-id":5,"id": 4,"run": 'Avg','title': "Sand & Silt", "measurement": "Average",},
    {'db-id':2,"internal-id":6,"id": 5,"run": '1','title': "Sand & Silt", "measurement": "Normal",},
    {'db-id':2,"internal-id":7,"id": 6,"run": '2','title': "Sand & Silt", "measurement": "Normal",},
    {'db-id':2,"internal-id":8,"id": 7,"run": '3','title': "Sand & Silt", "measurement": "Normal",},
    {'db-id':2,"internal-id":9,"id": 8,"run": 'Avg','title': "Sand & Silt", "measurement": "Average",},
    {'db-id':2,"internal-id":10,"id": 9,"run": '1','title': "Sand & Silt", "measurement": "Normal",},
    {'db-id':2,"internal-id":11,"id": 10,"run": '2','title': "Sand & Silt", "measurement": "Normal",},
    {'db-id':2,"internal-id":12,"id": 11,"run": '3','title': "Sand & Silt", "measurement": "Normal",},
    {'db-id':2,"internal-id":13,"id": 12,"run": 'Avg','title': "Sand & Silt", "measurement": "Average",},
     ]
    return row_data

def get_peaks_column_defs():

    columnDefs=[
    {'headerName':'Number', 'field' : 'internal-id', 'hide':False, 'filter': 'agNumberColumnFilter',
    'cellStyle':{
            # Set of color rules
            "styleConditions": [
                {
                    "condition": "[1].includes(params.value)",
                    "style": {"backgroundColor": "DeepSkyBlue", 'color':'white'},
                },{
                    "condition": "[2].includes(params.value)",
                    "style": {"backgroundColor": "Maroon", 'color':'white'},
                },{
                    "condition": "[3].includes(params.value)",
                    "style": {"backgroundColor": "Coral", 'color':'white'},
                },{
                    "condition": "[4].includes(params.value)",
                    "style": {"backgroundColor": "MediumPurple", 'color':'white'},
                },{
                    "condition": "[5].includes(params.value)",
                    "style": {"backgroundColor": "LimeGreen", 'color':'white'},
                },{
                    "condition": "[6].includes(params.value)",
                    "style": {"backgroundColor": "DarkSlateBlue", 'color':'white'},
                },{
                    "condition": "[7].includes(params.value)",
                    "style": {"backgroundColor": "Purple", 'color':'white'},
                },{
                    "condition": "[8].includes(params.value)",
                    "style": {"backgroundColor": "Gold", 'color':'white'},
                },{
                    "condition": "[9].includes(params.value)",
                    "style": {"backgroundColor": "DarkTurquoise", 'color':'white'},
                },{
                    "condition": "[10].includes(params.value)",
                    "style": {"backgroundColor": "DarkBlue", 'color':'white'},
                },{
                    "condition": "[11].includes(params.value)",
                    "style": {"backgroundColor": "HotPink", 'color':'white'},
                },{
                    "condition": "[12].includes(params.value)",
                    "style": {"backgroundColor": "Indigo", 'color':'white'},
                },
            ],
            # Default style if no rules apply
            "defaultStyle": {"backgroundColor": "mediumaquamarine"},
        }},
    {'headerName':'Sample', 'field':'sample','sortable':True,'filter':True},
    ]
    return columnDefs

def get_peaks_row_data():
    rowData=[{'internal-id':1,'sample':'1-1#1'},
        {'internal-id':2,'sample':'2-2#2'},
        {'internal-id':3,'sample':'2-2#2'},
        {'internal-id':4,'sample':'2-2#2'},
        {'internal-id':5,'sample':'2-2#2'},
        {'internal-id':6,'sample':'2-2#2'},
        {'internal-id':7,'sample':'2-2#2'},
        {'internal-id':8,'sample':'2-2#2'},
        {'internal-id':9,'sample':'2-2#2'},
        {'internal-id':10,'sample':'2-2#2'},
        {'internal-id':11,'sample':'2-2#2'},
        {'internal-id':12,'sample':'2-2#2'},
        {'internal-id':13,'sample':'2-2#2'},]
    return rowData

def get_peaks_default_col_defs():
    defaultColDef = {
    "flex": 1,
    "minWidth": 150,
    "filter": "agTextColumnFilter",}
    return defaultColDef

@app.callback(
    [Output('peaks-summary-grid', 'filterModel'),
     Output('peaks-summary-grid', 'style')],
    Input('my-grid', 'selectedRows'),
    State('peaks-summary-grid', 'filterModel')
)
def update_filter_model_and_visibility(selected_rows, current_filter_model):
    if not selected_rows:
        return {}, {'display': 'none'}

    conditions = []
    for row in selected_rows:
        conditions.append({
            'filterType': 'number',
            'type': 'equals',
            'filter': row['internal-id']
        })

    new_filter_model = {
        'internal-id': {
            'filterType': 'number',
            'operator': 'OR',
            'conditions': conditions
        }
    }

    return new_filter_model, {'display': 'block'}

app.layout = dbc.Container([
                    dag.AgGrid(
                    #CONTROL GRID
                        id="my-grid",  # use this id for update callbacks
                        columnDefs=get_control_column_defs(),
                        rowData=get_control_row_data(),
                        defaultColDef={"filter": True},
                        dashGridOptions={
                            "rowSelection": "multiple",
                            'suppressRowClickSelection': True,
                            'suppressMovableColumns': True,
                            'overflow':'scroll',
                            #'alwaysShowVerticalScroll':True,
                            "domLayout": "autoHeight",
                            'height':'200px'
                        },
                    ),
                    dag.AgGrid(
                        #SECONDARY GRID
                        columnDefs=get_peaks_column_defs(),
                        rowData=get_peaks_row_data(),
                        defaultColDef=get_peaks_default_col_defs(),
                        dashGridOptions={#"animateRows": False,
                        "domLayout": "autoHeight",
                        'overflow':'scroll',
                        'height' : '200px'
                        },
                        id="peaks-summary-grid",
                        filterModel={},
                        style={'display': 'none','overflow':'scroll'}  # starts off hidden, appears when rows are checked
                        )
], #closes container
fluid=True,
style={'display':'flex'},
className='full-container')

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

Hi @peachy_oasis

Thanks for the complete example :slight_smile:

The default for the maximum number of condition is 2. There is a nice error message from AG Grid about that if you use the dev tools to inspect the browser.

You can change that by adding "filterParams": {"maxNumConditions": 13},

More info here

You can find an example here:

You might also be interested in external filters instead

2 Likes