Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Column widths incorrectly calculated based on previous rowData when using autoSize in AgGrid #318

Open
petar-qb opened this issue Aug 8, 2024 · 1 comment
Labels
bug something broken P3 backlog

Comments

@petar-qb
Copy link

petar-qb commented Aug 8, 2024

Description

I'm using AgGrid component with columnSize="autoSize" configuration.
When the data filter value is changed, the grid column widths are calculated based on the previous instead on the latest rowData.

It seems like the DashAgGrid.updateColumnWidths() (and the inner gridApi.autoSizeAllColumns(skipHeader)) are called before the most recent rowData is set.

Expected behavior would be that the column widths are always aligned with the latest rowData.


How to Reproduce

Package version: dash-ag-grid==31.2.0

After running the code below, adjust the range slide filter as it's showed in the screen recoding (video below the code section):

import dash
from dash import dcc, html, Input, Output, callback
import dash_ag_grid as dag
import pandas as pd


# Initialize the Dash app
app = dash.Dash(__name__)


# Sample data
df = pd.DataFrame({
    'Column 1': [1, 2, 3, 4, 5, 6],
    'Column 2': ['A', 'B', 'C', 'VeryLongStringInputCell_VeryLongStringInputCell_VeryLongStringInputCell', 'D', 'E'],
    'Column 3': [10.5, 20.1, 30.2, 40.3, 50.4, 60.5],
})

# Layout
app.layout = html.Div([
    html.H1('Grid Page'),
    html.Div(id="outer_div_grid_id"),
    dcc.RangeSlider(id="filter_column_1_dropdown", min=1, max=6, step=1, value=[1, 6]),
])


@callback(
    Output("outer_div_grid_id", "children"),
    Input("filter_column_1_dropdown", "value"),
)
def update_outer_grid(dropdown_value):
    df_filtered = df[df["Column 1"].between(dropdown_value[0], dropdown_value[1], inclusive="both")]

    return [dag.AgGrid(
        id='grid_id',
        columnDefs=[{'field': col} for col in df.columns],
        columnSize="autoSize",
        rowData=df_filtered.to_dict('records'),
        defaultColDef={'resizable': True},
    )]


if __name__ == "__main__":
    app.run_server(debug=True, port=8051)
columSizeBug.mov
@BSd3v
Copy link
Collaborator

BSd3v commented Aug 8, 2024

Hello @petar-qb,

This probably works in a previous version, however, in the AG Grid update between these two versions, the rowData started updating asynchronously. Due to this, it broke selectedRows and also this.

However, it is important to note that in dash, you are not removing the component and causing it to be fresh, you are essentially updating the component, which means the grid is already initialized, therefore triggering the columnSize when updated.

Here is a way to update it with adjusting the id and you get the expected behavior:

import dash
from dash import dcc, html, Input, Output, callback
import dash_ag_grid as dag
import pandas as pd


# Initialize the Dash app
app = dash.Dash(__name__)


# Sample data
df = pd.DataFrame({
    'Column 1': [1, 2, 3, 4, 5, 6],
    'Column 2': ['A', 'B', 'C', 'VeryLongStringInputCell_VeryLongStringInputCell_VeryLongStringInputCell', 'D', 'E'],
    'Column 3': [10.5, 20.1, 30.2, 40.3, 50.4, 60.5],
})

# Layout
app.layout = html.Div([
    html.H1('Grid Page'),
    html.Div(id="outer_div_grid_id"),
    dcc.RangeSlider(id="filter_column_1_dropdown", min=1, max=6, step=1, value=[1, 6]),
])


@callback(
    Output("outer_div_grid_id", "children"),
    Input("filter_column_1_dropdown", "value"),
)
def update_outer_grid(dropdown_value):
    df_filtered = df[df["Column 1"].between(dropdown_value[0], dropdown_value[1], inclusive="both")]

    return [dag.AgGrid(
        id=f'grid_id{dropdown_value}',
        columnDefs=[{'field': col} for col in df.columns],
        columnSize="autoSize",
        rowData=df_filtered.to_dict('records'),
        defaultColDef={'resizable': True},
    )]


if __name__ == "__main__":
    app.run_server(debug=True, port=8051)

or you can use a chained callback:

import dash
from dash import dcc, html, Input, Output, callback
import dash_ag_grid as dag
import pandas as pd


# Initialize the Dash app
app = dash.Dash(__name__)


# Sample data
df = pd.DataFrame({
    'Column 1': [1, 2, 3, 4, 5, 6],
    'Column 2': ['A', 'B', 'C', 'VeryLongStringInputCell_VeryLongStringInputCell_VeryLongStringInputCell', 'D', 'E'],
    'Column 3': [10.5, 20.1, 30.2, 40.3, 50.4, 60.5],
})

# Layout
app.layout = html.Div([
    html.H1('Grid Page'),
    html.Div(id="outer_div_grid_id", children=
             [dag.AgGrid(
        id=f'grid_id',
        columnDefs=[{'field': col} for col in df.columns],
        columnSize="autoSize",
        rowData=df.to_dict('records'),
        defaultColDef={'resizable': True},
    )]),
    dcc.RangeSlider(id="filter_column_1_dropdown", min=1, max=6, step=1, value=[1, 6]),
])


@callback(
    Output("grid_id", "rowData"),
    Input("filter_column_1_dropdown", "value"),
)
def update_outer_grid(dropdown_value):
    df_filtered = df[df["Column 1"].between(dropdown_value[0], dropdown_value[1], inclusive="both")]

    return df_filtered.to_dict('records')

@callback(
    Output("grid_id", "columnSize"),
    Input("grid_id", "rowData"),
)
def update_size(_):
    return 'autoSize'


if __name__ == "__main__":
    app.run_server(debug=True, port=8051)

@gvwilson gvwilson changed the title [BUG] Column widths incorrectly calculated based on previous rowData when using autoSize in AgGrid Column widths incorrectly calculated based on previous rowData when using autoSize in AgGrid Aug 13, 2024
@gvwilson gvwilson added bug something broken P3 backlog labels Aug 13, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug something broken P3 backlog
Projects
None yet
Development

No branches or pull requests

3 participants