Hi @jinnyzor
Thank you very much for your reply.
This is my code:
# -*- coding: utf-8; py-indent-offset:4 -*-
import uuid
import dash_ag_grid as dag
from dash import Dash, html, Input, Output, State
from dash_bootstrap_components import RadioItems
app = Dash(__name__)
masterColumnDefs = [
{"headerName": "id", "field": "id", "hide": True},
{"headerName": "Client", "field": "Client", "editable": True},
{"headerName": "Project", "field": "Project", "editable": True},
{"headerName": "Discipline", "field": "Discipline", "editable": True},
{"headerName": "Load", "field": "Load", "editable": True},
{
"headerName": "Resources",
"field": "Resources",
"cellRenderer": "agGroupCellRenderer",
"cellRendererParams": {
"innerRenderer": "CustomGroupCellRenderer",
"innerRendererParams": {"col": "res"},
},
},
{
"headerName": "Progress",
"field": "Progress",
"cellRenderer": "agGroupCellRenderer",
"cellRendererParams": {
"innerRenderer": "CustomGroupCellRenderer",
"innerRendererParams": {"col": "av"},
},
},
]
detailResourcesDefs = [
{"headerName": "id2", "field": "id2", "hide": True},
{
"headerName": "Resource",
"field": "Resource",
"editable": True,
"cellRenderer": "agGroupCellRenderer",
"cellRendererParams": {"innerRenderer": "updateDetailData"},
},
{
"headerName": "Répartition",
"field": "Répartition",
"editable": True,
"cellRenderer": "agGroupCellRenderer",
"cellRendererParams": {"innerRenderer": "updateDetailData"},
},
{
"headerName": "Profil",
"field": "Profil",
"editable": True,
"cellRenderer": "agGroupCellRenderer",
"cellRendererParams": {"innerRenderer": "updateDetailData"},
},
]
detailProgressDefs = [
{"headerName": "id3", "field": "id3", "hide": True},
{
"headerName": "Date",
"field": "Date",
"editable": True,
"cellRenderer": "agGroupCellRenderer",
"cellRendererParams": {"innerRenderer": "updateDetailData"},
},
{
"headerName": "Progress",
"field": "Progress",
"editable": True,
"cellRenderer": "agGroupCellRenderer",
"cellRendererParams": {"innerRenderer": "updateDetailData"},
},
]
rowData = [
{
"id": str(uuid.uuid4()),
"Client": "Client 1",
"Project": "Project 1",
"Discipline": "Procédé",
"Load": 500,
"Resources": [
{
"id2": str(uuid.uuid4()),
"Resource": "R1",
"Répartition": "10%",
"Profil": "Pic à 50%",
},
{
"id2": str(uuid.uuid4()),
"Resource": "R2",
"Répartition": "70%",
"Profil": "Pic à 25%",
},
{
"id2": str(uuid.uuid4()),
"Resource": "R3",
"Répartition": "20%",
"Profil": "Pic à 80%",
},
{
"id2": str(uuid.uuid4()),
"Resource": "R4",
"Répartition": "20%",
"Profil": "Pic à 80%",
},
],
"Progress": [
{"id3": str(uuid.uuid4()), "Date": "17/08/2023", "Progress": "10%"},
{"id3": str(uuid.uuid4()), "Date": "17/11/2023", "Progress": "20%"},
{"id3": str(uuid.uuid4()), "Date": "17/12/2023", "Progress": "30%"},
],
},
{
"id": str(uuid.uuid4()),
"Client": "Client 1",
"Project": "Project 2",
"Discipline": "Installation générale",
"Load": 5000,
"Resources": [
{
"id2": str(uuid.uuid4()),
"Resource": "R10",
"Répartition": "10%",
"Profil": "Pic à 50%",
},
{
"id2": str(uuid.uuid4()),
"Resource": "R11",
"Répartition": "70%",
"Profil": "Pic à 25%",
},
{
"id2": str(uuid.uuid4()),
"Resource": "R12",
"Répartition": "20%",
"Profil": "Pic à 80%",
},
],
"Progress": [
{"id3": str(uuid.uuid4()), "Date": "17/08/2023", "Progress": "40%"},
{"id3": str(uuid.uuid4()), "Date": "17/11/2023", "Progress": "50%"},
{"id3": str(uuid.uuid4()), "Date": "17/12/2023", "Progress": "60%"},
{"id3": str(uuid.uuid4()), "Date": "17/01/2024", "Progress": "70%"},
],
},
]
app.layout = html.Div(
[
RadioItems(
id="columnToEdit",
className="btn-group btn-xs me-1",
inputClassName="btn-check",
labelClassName="btn btn-outline-secondary",
options=[
{"label": "Resources", "value": "Resources"},
{"label": "Progress", "value": "Progress"},
],
value="Resources",
),
dag.AgGrid(
id="aggrid",
enableEnterpriseModules=True,
rowData=rowData,
columnDefs=masterColumnDefs,
masterDetail=True,
detailCellRendererParams={
"suppressCallback": False,
"suppressDoubleClickExpand": True,
"detailColName": "Resources",
"detailGridOptions": {
"columnDefs": detailResourcesDefs,
},
},
),
]
)
@app.callback(
Output("aggrid", "getDetailResponse"),
Input("aggrid", "getDetailRequest"),
State("columnToEdit", "value"),
prevent_initial_call=True,
)
def get_response(request, colToEdit):
return request["data"][colToEdit]
@app.callback(
Output("aggrid", "detailCellRendererParams"),
Input("columnToEdit", "value"),
prevent_initial_call=True,
)
def update_detailCellRenderParams(colChange):
return {
"detailColName": colChange,
"detailGridOptions": {
"columnDefs": detailResourcesDefs
if colChange == "Resources"
else detailProgressDefs,
"enterMovesDownAfterEdit": True,
},
"suppressCallback": False,
}
if __name__ == "__main__":
app.run(debug=True)
I attempted to implement a column drill-down using the Master-Detail feature in AG Grid, inspired by Louis Moore’s blog post. However, I encountered challenges due to my very limited knowledge in JavaScript.
To overcome this issue, I devised a workaround by using RadioItems to select the column for editing and updating. While not as elegant, it serves my current needs.
Currently, I am working on two tasks:
- CustomGroupCellRender:
- I aim to utilize this feature to achieve the following in the Master grid:
- Display a list of different Resources (as opposed to objects) in the Resources column.
- Show the maximum value of Progress in the Progress column.
- updateDetailData:
- I intend to update the rowData immediately upon modifying a cell in the details grid.
I have started working on these tasks but lack the expertise in JavaScript to fully implement them."
var dagcomponentfuncs = window.dashAgGridComponentFunctions = window.dashAgGridComponentFunctions || {};
dagcomponentfuncs.CustomGroupCellRenderer = function (props) {
if (props.colDef.field === "Resources") {
var resourceNames = props.data.Resources.map(resource => resource.Resource).join(", ");
return resourceNames;
} else if (props.colDef.field === "Progress") {
var progressValues = props.data.Progress.map(progress => progress.Progress);
var maxProgress = Math.max(...progressValues);
return maxProgress + "%";
} else {
return props.colDef.field;
}
};
dagcomponentfuncs.updateDetailData = function (props) {
console.log(props.api.gridOptionsService.gridOptions.rowData)
const {setData, data} = props;
console.log(setData)
console.log(data)
function onClick() {
//var newData = props.api.gridOptionsService.gridOptions.rowData
props.api.gridOptionsService.gridOptions.api.setRowData(data);
setData(data);
}
return React.createElement(
'div',
{
onClick: onClick,
className: props.className,
},
props.value
);
};
I would be very grateful for a helping hand.
Sam