plotly / dash-ag-grid

Dash AG Grid is a high-performance and highly customizable component that wraps AG Grid, designed for creating rich datagrids.
https://dash.plotly.com/dash-ag-grid
MIT License
176 stars 28 forks source link

applyTransaction `add` forces the grid to scroll to the top #308

Closed BSd3v closed 4 months ago

BSd3v commented 4 months ago

Here is a test example:

import dash
import dash_ag_grid as dag
import pandas as pd
from dash import *
import json

app = Dash(__name__)

columnDefs = [
    {
        "headerName": "Make",
        "field": "make",
    },
    {
        "headerName": "Model",
        "field": "model",
    },
    {"headerName": "Price", "field": "price"},
]

rowData = [
    {"make": "Toyota", "model": "Celica", "price": 35000},
    {"make": "Ford", "model": "Mondeo", "price": 32000},
    {"make": "Porsche", "model": "Boxster", "price": 72000},
]

extraData = [
    {"make": "Subaru", "model": "Impreza", "price": 35000},
    {"make": "Mazda", "model": "CX-5", "price": 32000},
    {"make": "Honda", "model": "Pilot", "price": 72000},
]

defaultColDef = {"editable": True}

app.layout = html.Div(
    [
        dcc.Markdown(
            "In this grid, the __Make__ column has a popup below the cell,  the __Model__ has a popup above the cell, and the __Price__ has the default (in cell) editor."
        ),
        dag.AgGrid(
            columnDefs=columnDefs,
            rowData=rowData,
            defaultColDef=defaultColDef,
            columnSize="sizeToFit",
            id="grid",
            dashGridOptions={"editType": "fullRow"},
        ),
        html.Div(id="data"),
        html.Div(id="virtualData"),
        html.Button("edit mode", id="editMode", n_clicks=0),
        html.Button(id="reset", children="reset", n_clicks=0),
        html.Button("addRow", id="addRow", n_clicks=0),
        html.Button("addRow_notAsync", id="addRow_notAsync", n_clicks=0),
    ],
    style={"margin": 20},
)

@app.callback(Output("grid", "dashGridOptions"), Input("editMode", "n_clicks"))
def toggleMode(n):
    if n:
        assert n > 0
        if n % 2 == 0:
            return {"editType": "fullRow"}
        else:
            return {"editType": None}

@app.callback(
    Output("data", "children"),
    Input("grid", "cellValueChanged"),
    Input("grid", "rowData"),
)
def rowDataUpdate(c, d):
    if d:
        return json.dumps(d)

@app.callback(
    Output("grid", "rowData"),
    Output("addRow", "n_clicks"),
    Output("addRow_notAsync", "n_clicks"),
    Input("reset", "n_clicks"),
)
def reset(n):
    if n > 0:
        return rowData, 0, 0
    return no_update, no_update, no_update

@app.callback(
    Output("grid", "rowTransaction"),
    Input("addRow", "n_clicks"),
    Input("addRow_notAsync", "n_clicks"),
)
def addRows(n, n2):
    if n or n2:
        if ctx.triggered_id == "addRow":
            return {"add": [extraData[n%3 - 1]]}
        if ctx.triggered_id == "addRow_notAsync":
            return {"add": [extraData[n2%3 - 1]], "async": False}

@app.callback(
    Output("virtualData", "children"),
    Input("grid", "cellValueChanged"),
    Input("grid", "virtualRowData"),
)
def virtualDataUpdate(c, d):
    if d:
        return json.dumps(d)

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

Once you add more data then there is available in the scroll area, scroll to the bottom and add, it will pop you up to the top of the data.

Expected behaviour should be to stay on the currently focused cell.

Relevant AG Grid docs: https://www.ag-grid.com/react-data-grid/data-update-transactions/

BSd3v commented 4 months ago

So, to avert this type of interaction, you need to provide a getRowId.