Hi all! This is going to be more of a comment than a question but I wanted to share it in case it’s useful for somebody else
Use case: changing grid columns and their order programatically, that is, with a callback instead of with user interaction.
Environment: dash-ag-grid==2.0.0rc2
Main takeaways:
- It’s necessary to update both
columnDefs
andcolumnState
for the change incolumnDefs
to be effective; otherwise we need to trigger the callback twice:
# this works
@callback(
Output("grid4", 'columnDefs'),
Output("grid4", "columnState"),
Input('b2', 'n_clicks'),
prevent_initial_call=True
)
def update_grids_cols_4(_) :
return columnDefs2, []
- We could also target
resetColumnState
as Output, but in that case updating it at the same time/in the same callback ascolumnDefs
doesn’t work, we would need to use a chained callback:
# this works too, but it's less efficient
@callback(
Output("grid3", 'columnDefs'),
Input('b', 'n_clicks'),
prevent_initial_call=True
)
def update_grids_cols(_) :
return columnDefs2
@callback(
Output("grid3", "resetColumnState"),
Input("grid3", 'columnDefs'),
prevent_initial_call=True
)
def update_grids_cols(_) :
return True
- If you want to learn more about
columnState
: Dash
Full code to replicate the issue and test things!:
import dash_ag_grid as dag
from dash import Dash, html, dcc, callback, Input, Output
import pandas as pd
df = pd.read_csv("https://raw.githubusercontent.com/plotly/datasets/master/ag-grid/olympic-winners.csv")
app = Dash(__name__)
columnDefs1 = [
{"field": "athlete"},
{"field": "age"},
{"field": "country"},
{"field": "sport"},
]
columnDefs2 = [
{'field':'year'},
{"field": "age"},
{"field": "sport"},
{"field": "athlete"},
{"field": "country"},
]
def grid(colDefs, idGrid=''):
return dag.AgGrid(
id=idGrid,
columnDefs=colDefs,
rowData=df.to_dict("records"),
style={'height':'200px'}
)
grid1 = grid(columnDefs1)
grid2 = grid(columnDefs2)
grid3 = grid(columnDefs1,"grid3")
grid4 = grid(columnDefs1,"grid4")
app.layout = html.Div(
[
html.Div("Start state"),
grid1,
html.Div("Desired end state"),
grid2,
html.Br(),
dcc.Markdown("""
**Actual behaviour:**
If we only use `columnDefs` as Output, we need two clicks to completely overwrite previous `columnDefs`, with only one click they are combined
```
@callback(
Output("grid3", 'columnDefs'),
Input('b', 'n_clicks'),
prevent_initial_call=True
)
def update_grids_cols(_) :
return columnDefs2
```
"""),
html.Button(id='b1', children='Change colDefs in 2 clicks!'),
grid3,
dcc.Markdown("""
**Corrected behaviour:**
Using both `columnDefs` and `columnState`.
```
@callback(
Output("grid4", 'columnDefs'),
Output("grid4", "columnState"),
Input('b2', 'n_clicks'),
prevent_initial_call=True
)
def update_grids_cols_4(_) :
return columnDefs2, []
```
"""),
html.Button(id='b2', children='Change colDefs in 1 click!'),
grid4,
],
style={"margin": 20},
)
@callback(
Output("grid3", 'columnDefs'),
Input('b1', 'n_clicks'),
prevent_initial_call=True
)
def update_grids_cols_3(_) :
return columnDefs2
@callback(
Output("grid4", 'columnDefs'),
Output("grid4", "columnState"),
Input('b2', 'n_clicks'),
prevent_initial_call=True
)
def update_grids_cols_4(_) :
return columnDefs2, []
if __name__ == "__main__":
app.run_server(debug=True)