dash-ag-grid
dash-ag-grid copied to clipboard
persistence does not work when editing cell
Based on the Docs:. We would like to make the data persist after editing the table. The persisted_props might be rowData. However, the persistence does not work as in the sample below:
"""
Accessing Row Data in an editable grid
"""
import dash
import dash_ag_grid as dag
from dash import Dash, html, dcc, Input, Output, State,ctx
import plotly.express as px
import pandas as pd
import json
app = Dash(__name__)
df = px.data.medals_wide()
app.layout = html.Div(
[
dcc.Markdown(id= 'dummy-input', children="Example of using `rowData` in a callback with an editable grid and added persistence to cell"),
dag.AgGrid(
id="editing-grid",
columnDefs=[{"field": i} for i in df.columns],
rowData=df.to_dict("records"),
columnSize="sizeToFit",
defaultColDef={"editable": True},
persistence=True,
persisted_props=['rowData'],
),
],
style={"margin": 20},
)
if __name__ == "__main__":
app.run_server(debug=True)
A workaround is to use dcc.Store() as below:
"""
Accessing Row Data in an editable grid
"""
import dash
import dash_ag_grid as dag
from dash import Dash, html, dcc, Input, Output, State,ctx
import plotly.express as px
import pandas as pd
import json
app = Dash(__name__)
df = px.data.medals_wide()
app.layout = html.Div(
[
dcc.Markdown(id= 'dummy-input', children="Example of using `rowData` in a callback with an editable grid and added persistence to cell"),
dag.AgGrid(
id="editing-grid",
columnDefs=[{"field": i} for i in df.columns],
rowData=df.to_dict("records"),
columnSize="sizeToFit",
defaultColDef={"editable": True},
),
dcc.Store(id='memory',storage_type = 'session'),
html.Div(id="editing-grid-output2"),
],
style={"margin": 20},
)
@app.callback(
Output("memory", "data"),
Output("editing-grid", "rowData"),
Input("editing-grid", "cellValueChanged"),
State("editing-grid", "rowData"),
State("memory", "data"),
)
def update(cell,rows,saved_rows):
if saved_rows is None:
saved_rows = df.to_dict("records")
if cell is None:
return saved_rows, saved_rows
else:
return rows,rows
if __name__ == "__main__":
app.run_server(debug=True)
Hello @RunQi-Han,
This is actually an issue with how the grid manipulates the rowData, they manipulate the variable in place, so there is no way for dash to distinguish that the rowData has changed.
Unfortunately, this might be something that we cant do because it could cause a performance hit to separate them.
May revisit later.
For now, this work around for persistence will need to mainstream.
Hello @RunQi-Han,
This is actually an issue with how the grid manipulates the
rowData, they manipulate the variable in place, so there is no way for dash to distinguish that therowDatahas changed.Unfortunately, this might be something that we cant do because it could cause a performance hit to separate them.
May revisit later.
For now, this work around for persistence will need to mainstream.
@BSd3v thanks for your explanation.
Hi! Here's an updated version of the workaround that takes advantage of Patch() (partial property updates) to improve performance, especially with large datasets:
import dash
import dash_ag_grid as dag
from dash import Dash, html, dcc, Input, Output, State, ctx, Patch, callback
import plotly.express as px
import pandas as pd
app = Dash(__name__)
df = px.data.gapminder()
# df["id"] = df.index # optional
app.layout = html.Div(
[
dag.AgGrid(
id="editing-grid",
columnDefs=[{"field": i} for i in df.columns if i != 'id'],
rowData=df.to_dict("records"),
columnSize="sizeToFit",
defaultColDef={"editable": True},
#getRowId="params.data.id" # optional
),
dcc.Store(id='memory',storage_type = 'session', data=[]),
],
style={"margin": 20},
)
@callback(
Output("memory", "data"),
Output("editing-grid", "rowData"),
Input("editing-grid", "cellValueChanged"),
State("memory", "data")
# it's important that prevent_initial_call=False (the default)
)
def update(cells, edits):
row_id_var = 'rowIndex' # you could use rowId instead
if cells :
cells_info = [{k:c[k] for k in [row_id_var, 'colId', 'value']} for c in cells]
# you may want to include some logic to check if previous edits have been made to the same cells and remove those
# keeping old edits won't cause a problem anyway
edits += cells_info
return edits, dash.no_update
else :
saved_rows = Patch()
for e in edits:
index = e[row_id_var]
saved_rows[index][e['colId']] = e['value']
return dash.no_update, saved_rows
if __name__ == "__main__":
app.run_server(debug=True)