Hello guys,
I have switched from Dash DataTable to DASH AG GRID after this post:
QUESTION ABOUT FORMATTING SOME VALUES IN A DASH DATATABLE (WHEN USING A TRANSPOSED TABLE)
In the question above, I focused on a specific problem, but after switching my table to AG GRID I started to find new limitations as I have text, boolean, and others data types and I can’t find solutions to deal with it.
Below are some of the new issues/limitations I found:
-
Sometimes, the user does not add/change anything but because of as the DASH AG GRID recognize the data types the changes are triggered;
-
I can’t highlight a Specific cell based on which one was changed
-
I can’t find a way to force the cells to render the entire values inside the cells without the …

Iin dash datatable we could deal with this kind of problem by simple using:
style_data={"whiteSpace": "normal",
"overflow": "hidden",
"textOverflow": "ellipsis"}
__________________________________
Below I will add a Minimal reproducible example
import dash
from dash import html, Dash, Output, Input, State, dcc
import dash_ag_grid as dag
import pandas as pd
list_of_vals = [
{
"Val ID": "9729",
"Year Col": "2017",
"Hours Col": 1253.0,
"Value Col": 31950000.0,
"Text Col": "testing a random text which is long enough to wrap",
"Bool Col": "No",
"Date Col": "2023/01/02",
"Link Col": "https://www.google.com",
},
{
"Val ID": "9733",
"Year Col": "2016",
"Hours Col": 2541.0,
"Value Col": 29995000.0,
"Text Col": "testing a random text which is long enough to wrap",
"Bool Col": "Yes",
"Date Col": "2023/01/02",
"Link Col": "https://www.google.com",
},
{
"Val ID": "9837",
"Year Col": "2019",
"Hours Col": 566.0,
"Value Col": 34900000.0,
"Text Col": "testing a random text which is long enough to wrap",
"Bool Col": "No",
"Date Col": "2023/01/02",
"Link Col": "https://www.google.com",
},
{
"Val ID": "9507",
"Year Col": "2013",
"Hours Col": 2732.0,
"Value Col": 26000000.0,
"Text Col": "testing a random text which is long enough to wrap",
"Bool Col": "Yes",
"Date Col": "2023/01/02",
"Link Col": "https://www.google.com",
},
{
"Val ID": "9805",
"Year Col": "2018",
"Hours Col": 1543.0,
"Value Col": 31500000.0,
"Text Col": "testing a random text which is long enough to wrap",
"Bool Col": "Yes",
"Date Col": "2023/01/02",
"Link Col": "https://www.google.com",
},
]
df = pd.DataFrame(list_of_vals)
df = df.set_index("Val ID").T
df = df.reset_index().rename(columns={"index": "Val ID"})
data_list = [item for item in df.to_dict(orient="records")]
columns_list = list(df.columns)
app = Dash()
app.layout = html.Div(
[
dcc.Store(id="changed-cell", data=[]),
html.H2("Testing Dash AG GRID"),
dag.AgGrid(
rowData=data_list,
columnDefs=[{"field": "Val ID", "editable": False}]
+ [
{
"field": c,
"valueFormatter": {"function": "FormatNumbersByRow(params)"},
# "editable": {"function": "params.data['Val ID'] !== 'Year Col'"}
}
for c in columns_list
if c != "Val ID"
],
defaultColDef={"editable": True, "flex": 1},
dashGridOptions={
"undoRedoCellEditing": False,
"undoRedoCellEditingLimit": 20,
},
id="ag-grid-table",
),
dcc.Store(id="original-data", data=data_list),
html.Div(id="edited-table-output"),
],
style={"padding": "16px"},
)
@app.callback(
Output("changed-cell", "data", allow_duplicate=True),
Input("ag-grid-table", "cellValueChanged"),
Input("ag-grid-table", "rowData"),
# Input("ag-grid-table", "active_cell"),
State("changed-cell", "data"),
State("original-data", "data"),
prevent_initial_call=True,
)
def update_table(changed_value, data_table, changes_stored, og_data): # active_cell,
triggered_id = [t["prop_id"] for t in dash.callback_context.triggered][0]
if changed_value is not None:
key = changed_value[0]["colId"]
changed_column = changed_value[0]["data"]["Val ID"]
row_index = changed_value[0]["rowId"]
new_value = changed_value[0]["value"]
change_id = f"{key}-{changed_column}"
for row in og_data:
if row["Val ID"] == changed_column:
print(row)
old_value = row[key]
else:
pass
new_changes = {
"change_id": change_id,
"val-ID": key,
"index_row": row_index,
"column": changed_column,
"old_value": old_value,
"new_value": new_value,
}
changes_stored = [
changes_stored
for changes_stored in changes_stored
if changes_stored["change_id"] != change_id
]
changes_stored.append(new_changes)
return changes_stored
return dash.no_update
def gen_update_row_btn(changes):
return html.Div(
[
html.Div(
[
html.Div(
[html.Div(f"val-ID: "), html.B(changes["val-ID"])],
style={"display": "flex", "gap": "8px", "marginRight": "16px"},
),
html.Div(
[html.Div(f"Changed Column: "), html.B(changes["column"])],
style={"display": "flex", "gap": "8px", "marginRight": "16px"},
),
html.Div(
[
html.Div(f"Old Value & Type: "),
html.B(
f'{changes["old_value"]} - {type(changes["old_value"])}'
),
],
style={"display": "flex", "gap": "8px", "marginRight": "16px"},
),
html.Div(
[
html.Div(f"New Value & Type: "),
html.B(
f'{changes["new_value"]} - {type(changes["new_value"])}'
),
],
style={"display": "flex", "gap": "8px", "marginRight": "16px"},
),
],
style={"display": "flex"},
),
],
className="",
)
@app.callback(Output("edited-table-output", "children"), Input("changed-cell", "data"))
def update_d(cc_data):
print(cc_data)
if cc_data == []:
return None
else:
list_of_changes_to_confirm = [gen_update_row_btn(change) for change in cc_data]
if len(cc_data) == 0:
return None
elif len(cc_data) == 1:
return html.Div(
[
html.Div(list_of_changes_to_confirm),
html.Div(
html.Button(
"Confirm Changes",
id={
"type": "confirm-all-btn",
"id": "test",
},
className="",
),
className="textCenter bottom16",
),
]
)
else:
return html.Div(
[
html.Div(list_of_changes_to_confirm),
html.Div(
html.Button(
"Confirm Changes",
id={
"type": "confirm-all-btn",
"id": "test",
},
className="",
),
className="textCenter bottom16",
),
]
)
if __name__ == "__main__":
app.run_server(debug=True, port=8054)
and the content of assets/agGridFunctions.js (I’ve added the console.log to help to validate it, but it only works for the numerical values =/ )
var dagfuncs = (window.dashAgGridFunctions = window.dashAgGridFunctions || {});
dagfuncs.Intl = Intl;
dagfuncs.FormatNumbersByRow = function(params) {
if (isNaN(params.value)) {
return params.value;
}
if (params.data["Val ID"] == "Text Col") {
console.log(params.value);
return params.value.toString();
}
if (params.data["Val ID"] == "Hours Col") {
console.log(params.value);
return parseInt(params.value);
}
if (params.data["Val ID"] == "Bool Col") {
console.log(params.value);
return params.value.toLowerCase() === 'yes';
}
if (params.data["Val ID"] == "Value Col") {
return Intl.NumberFormat("en-US", {
style: "currency",
currency: "USD",
minimumFractionDigits: 0,
maximumFractionDigits: 0,
}).format(params.value);
}
}
If you have any info about how to proceed to solve any of the issues I mentioned above, I would love to know it; Any help is appreciated




