Cannot update columnDefs in AG Grid

Hi!

I have a separate file for columnDefs from from I am importing four of those:

from column_info_data import columnDefs_1, columnDefs_2, columnDefs_3, columnDefs_4

I have following AG Grid table:

@callback(
        Output("table-from-sql", "children"),
        Input("filtered-SQL-data", "data")
)

def populate_datatable(json_data):
    dff = pd.read_json(json_data, orient="split")
    table = grid.AgGrid(
            id="sql-table",
            rowData=dff.to_dict("records"), 
            columnDefs=columnDefs_2,             # <===== not updating
            defaultColDef={
                "resizable": True,
                "sortable": True,
                "filter": True,
                "floatingFilter": True,
                "editable": True,
                "minWidth":125
            },
            columnSize="sizeToFit",
            dashGridOptions={
                "undoRedoCellEditing": True,
                "rowDragManaged": True,
                "animateRows": True,
                "rowDragMultiRow": True,
                "suppressRowClickSelection" : True,
                "rowSelection": "multiple",
                "rowDragEntireRow": True,
            },
        )
    return table

What I am trying to do is to call one of columnDefs depending on condition (two dropdowns).
For that purpose, I used the documentation here and wrote the callback below, but it is not working.

@callback(
        Output("sql-table", "columnDefs"),
        Input("month-dropdown", "value"),
        Input("year-dropdown", "value")
)

def col_def(month, year):
        if month == None and year == None:
            return columnDefs_1
        elif month != None and year == None:
            return columnDefs_3
        elif month == None and year != None:
            return columnDefs_4
        return columnDefs_2

The callback is supposed to check two dropdowns and based on their values, return one of columnDefs, but it is not working.

Any ideas why it might not work?

Thanks for help in advance.

Hello @mrel,

To confirm, you are using 2.3.0 dag?

It also doesn’t look like you id matches the grid’s id.

Hi @jinnyzor ,

Oops. Yes, I corrected grid’s id the Output (also edited in the post above). Still not working.

Btw, the only difference, between different columnDefs that I have, is hidden columns. Some columns are visible in one columnDefs and hidden in others.

Yes, I am using 2.3.0
image

Can you give a full MRE?

Here is an example below.

The idea is that there are two dropdowns (for month and for year) and when dropdowns change, grid also changes.
Example:
If there is are values chosen for both dropdowns, then “year” and “month” columns should be hidden.
If I remove month dropdown value (but year is still selected), then “month” column should appear.
If I select a month from dropdown again, the “month” column should disappear again.

Whether a column is visible or hidden, I am manipulaing via "hide":"True" line in different columnDefs.

import dash
from dash import Dash, html, dcc, Input, Output, State, no_update, ctx, callback
import dash_bootstrap_components as dbc
import dash_ag_grid as grid
import pandas as pd
import numpy as np

#-------------------------------------------------------------------------------------------------------------------------------

columnDefs_1 = [
    {
        "headerName": "Entry",  # Name of table displayed in app
        "field": "entry",       # ID of table (needs to be the same as SQL column name)
        "type":"numericColumn",
        "editable":False,
        # "rowDrag": False,         # only need to activate on the first row for all to be draggable
        "checkboxSelection": True,  # only need to activate on the first row
        # "hide":"True",
        "floatingFilter": False
    },
    {
        "headerName": "Year",
        "field": "year",
        # "type": "rightAligned",
        # "editable":False,
        "filter": "numericColumn",
        # "hide":"True",
        "floatingFilter": False
    },
    {
        "headerName": "Month",
        "field": "month",
        # "type": "rightAligned",
        # "editable":False,
        "filter": "agTextColumnFilter",
        # "hide":"True",
        "floatingFilter": False,
        "cellEditor":"agSelectCellEditor",
        "cellEditorParams":{"values":[
                                        "January",
                                        "February",
                                        "March",
                                        "April",
                                        "May",
                                        "June",
                                        "July",
                                        "August",
                                        "September",
                                        "October",
                                        "November",
                                        "December"
                                    ]}
    }
]

columnDefs_2 = [
    {
        "headerName": "Entry",  # Name of table displayed in app
        "field": "entry",       # ID of table (needs to be the same as SQL column name)
        "type":"numericColumn",
        "editable":False,
        # "rowDrag": False,         # only need to activate on the first row for all to be draggable
        "checkboxSelection": True,  # only need to activate on the first row
        # "hide":"True",
        "floatingFilter": False
    },
    {
        "headerName": "Year",
        "field": "year",
        # "type": "rightAligned",
        # "editable":False,
        "filter": "numericColumn",
        "hide":"True",
        "floatingFilter": False
    },
    {
        "headerName": "Month",
        "field": "month",
        # "type": "rightAligned",
        # "editable":False,
        "filter": "agTextColumnFilter",
        "hide":"True",
        "floatingFilter": False,
        "cellEditor":"agSelectCellEditor",
        "cellEditorParams":{"values":[
                                        "January",
                                        "February",
                                        "March",
                                        "April",
                                        "May",
                                        "June",
                                        "July",
                                        "August",
                                        "September",
                                        "October",
                                        "November",
                                        "December"
                                    ]}
    }
]

columnDefs_3 = [
    {
        "headerName": "Entry",  # Name of table displayed in app
        "field": "entry",       # ID of table (needs to be the same as SQL column name)
        "type":"numericColumn",
        "editable":False,
        # "rowDrag": False,         # only need to activate on the first row for all to be draggable
        "checkboxSelection": True,  # only need to activate on the first row
        # "hide":"True",
        "floatingFilter": False
    },
    {
        "headerName": "Year",
        "field": "year",
        # "type": "rightAligned",
        # "editable":False,
        "filter": "numericColumn",
        # "hide":"True",
        "floatingFilter": False
    },
    {
        "headerName": "Month",
        "field": "month",
        # "type": "rightAligned",
        # "editable":False,
        "filter": "agTextColumnFilter",
        "hide":"True",
        "floatingFilter": False,
        "cellEditor":"agSelectCellEditor",
        "cellEditorParams":{"values":[
                                        "January",
                                        "February",
                                        "March",
                                        "April",
                                        "May",
                                        "June",
                                        "July",
                                        "August",
                                        "September",
                                        "October",
                                        "November",
                                        "December"
                                    ]}
    }
]

columnDefs_4 = [
    {
        "headerName": "Entry",  # Name of table displayed in app
        "field": "entry",       # ID of table (needs to be the same as SQL column name)
        "type":"numericColumn",
        "editable":False,
        # "rowDrag": False,         # only need to activate on the first row for all to be draggable
        "checkboxSelection": True,  # only need to activate on the first row
        # "hide":"True",
        "floatingFilter": False
    },
    {
        "headerName": "Year",
        "field": "year",
        # "type": "rightAligned",
        # "editable":False,
        "filter": "numericColumn",
        "hide":"True",
        "floatingFilter": False
    },
    {
        "headerName": "Month",
        "field": "month",
        # "type": "rightAligned",
        # "editable":False,
        "filter": "agTextColumnFilter",
        # "hide":"True",
        "floatingFilter": False,
        "cellEditor":"agSelectCellEditor",
        "cellEditorParams":{"values":[
                                        "January",
                                        "February",
                                        "March",
                                        "April",
                                        "May",
                                        "June",
                                        "July",
                                        "August",
                                        "September",
                                        "October",
                                        "November",
                                        "December"
                                    ]}
    }
]

#-------------------------------------------------------------------------------------------------------------------------------

@callback(
        Output("table-from-sql", "children"),
        Input("filtered-SQL-data", "data")
)

def populate_datatable(json_data):
    dff = pd.DataFrame(np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]),
                   columns=["entry", "year", "month"])
    table = grid.AgGrid(
            id="sql-table",
            rowData=dff.to_dict("records"), 
            columnDefs=columnDefs_1,             # <===== not updating
            defaultColDef={
                "resizable": True,
                "sortable": True,
                "filter": True,
                "floatingFilter": True,
                "editable": True,
                "minWidth":125
            },
            columnSize="sizeToFit",
            dashGridOptions={
                "undoRedoCellEditing": True,
                "rowDragManaged": True,
                "animateRows": True,
                "rowDragMultiRow": True,
                "suppressRowClickSelection" : True,
                "rowSelection": "multiple",
                "rowDragEntireRow": True,
            },
        )
    return table

@callback(
        Output("sql-table", "columnDefs"),
        Input("month-dropdown", "value"),
        Input("year-dropdown", "value")
)

def col_def(month, year):
        if month == None and year == None:
            return columnDefs_1
        elif month != None and year == None:
            return columnDefs_3
        elif month == None and year != None:
            return columnDefs_4
        return columnDefs_2

#-------------------------------------------------------------------------------------------------------------------------------
app = Dash(__name__)

app.layout = dbc.Container([
    dbc.Row([
        dbc.Col([
            dcc.Interval(id='interval_pg', interval=86400000*7, n_intervals=0),  # activated once/week or when page refreshed
            html.Div(
                dcc.Dropdown(
                    ["January", "February", "March"],
                    "January",
                    id="month-dropdown"
                )
            )
        ],width=3),
        dbc.Col(html.Div(), width=1),
        dbc.Col(
            html.Div(
                dcc.Dropdown(
                    [2021, 2022, 2023],
                    2021,
                    id="year-dropdown"
                )
            ),
            width=2
        )
    ]),
    dbc.Row(
        dbc.Col(
            html.Div(id='table-from-sql')
        )
    ),
    dbc.Row([
        dbc.Col([
            dcc.Store(id="sql-data", data=0),
            dcc.Store(id="filtered-SQL-data", data=0),
            dcc.Interval(id='interval', interval=1000),
            dcc.Interval(id='interval1', interval=1000)
        ])
    ])
])

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

@mrel

There is a much easier way to do this. Instead of defining 4 different colunDefs you can just update the columnState in the callback. See the Column State section of the Dash AG Grid docs for more info:

Here’s a full example based on your MRE


import dash
from dash import Dash, html, dcc, Input, Output, State, no_update, ctx, callback
import dash_bootstrap_components as dbc
import dash_ag_grid as grid
import pandas as pd
import numpy as np

# -------------------------------------------------------------------------------------------------------------------------------

columnDefs_1 = [
    {
        "headerName": "Entry",  # Name of table displayed in app
        "field": "entry",  # ID of table (needs to be the same as SQL column name)
        "type": "numericColumn",
        "editable": False,
        # "rowDrag": False,         # only need to activate on the first row for all to be draggable
        "checkboxSelection": True,  # only need to activate on the first row
        # "hide":"True",
        "floatingFilter": False,
    },
    {
        "headerName": "Year",
        "field": "year",
        # "type": "rightAligned",
        # "editable":False,
        "filter": "numericColumn",
        # "hide":"True",
        "floatingFilter": False,
    },
    {
        "headerName": "Month",
        "field": "month",
        # "type": "rightAligned",
        # "editable":False,
        "filter": "agTextColumnFilter",
        # "hide":"True",
        "floatingFilter": False,
        "cellEditor": "agSelectCellEditor",
        "cellEditorParams": {
            "values": [
                "January",
                "February",
                "March",
                "April",
                "May",
                "June",
                "July",
                "August",
                "September",
                "October",
                "November",
                "December",
            ]
        },
    },
]


# -------------------------------------------------------------------------------------------------------------------------------


@callback(Output("table-from-sql", "children"), Input("filtered-SQL-data", "data"))
def populate_datatable(json_data):
    dff = pd.DataFrame(
        np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]), columns=["entry", "year", "month"]
    )
    table = grid.AgGrid(
        id="sql-table",
        rowData=dff.to_dict("records"),
        columnDefs=columnDefs_1,  # <===== not updating
        defaultColDef={
            "resizable": True,
            "sortable": True,
            "filter": True,
            "floatingFilter": True,
            "editable": True,
            "minWidth": 125,
        },
        columnSize="sizeToFit",
        dashGridOptions={
            "undoRedoCellEditing": True,
            "rowDragManaged": True,
            "animateRows": True,
            "rowDragMultiRow": True,
            "suppressRowClickSelection": True,
            "rowSelection": "multiple",
            "rowDragEntireRow": True,
        },
    )
    return table


@callback(
    Output("sql-table", "columnState"),
    Input("month-dropdown", "value"),
    Input("year-dropdown", "value"),
    prevent_initial_call=True,
)
def col_def(month, year):
    return [
        {"colId": "entry"},
        {"colId": "year", "hide": year is None},
        {"colId": "month", "hide": month is None},
    ]


# -------------------------------------------------------------------------------------------------------------------------------
app = Dash(__name__, suppress_callback_exceptions=True)

app.layout = dbc.Container(
    [
        dbc.Row(
            [
                dbc.Col(
                    [
                        dcc.Interval(
                            id="interval_pg", interval=86400000 * 7, n_intervals=0
                        ),  # activated once/week or when page refreshed
                        html.Div(
                            dcc.Dropdown(
                                ["January", "February", "March"],
                                "January",
                                id="month-dropdown",
                            )
                        ),
                    ],
                    width=3,
                ),
                dbc.Col(html.Div(), width=1),
                dbc.Col(
                    html.Div(
                        dcc.Dropdown([2021, 2022, 2023], 2021, id="year-dropdown")
                    ),
                    width=2,
                ),
            ]
        ),
        dbc.Row(dbc.Col(html.Div(id="table-from-sql"))),
        dbc.Row(
            [
                dbc.Col(
                    [
                        dcc.Store(id="sql-data", data=0),
                        dcc.Store(id="filtered-SQL-data", data=0),
                        dcc.Interval(id="interval", interval=1000),
                        dcc.Interval(id="interval1", interval=1000),
                    ]
                )
            ]
        ),
    ]
)

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


3 Likes

Thank you, @AnnMarieW , this works perfectly. Special thanks for linking the documentation. It is clear now.