It is possible to nest Master / Detail grids. There is no special configuration required to do this, you just configure another Detail Grid to also act as a Master Grid.
The following snippet illustrates how to achieve nesting by configuring Detail Grids to also act as Master Grids.
// Level 3 (bottom level), Detail Grid only, no Master / Detail configuration
const gridOptionsLevel3 = {
...
}
// Level 2, configured to be a Master Grid and use Level 3 grid as Detail Grid,
const gridOptionsLevel2 = {
masterDetail: true,
detailCellRendererParams: {
detailGridOptions: gridOptionsLevel3,
getDetailRowData: function (params) {
...
}
}
...
}
// Level 1, configured to be a Master Grid and use Level 2 grid as Detail Grid,
const gridOptionsLevel1 = {
masterDetail: true,
detailCellRendererParams: {
detailGridOptions: gridOptionsLevel2,
getDetailRowData: function (params) {
...
}
}
...
}Below shows a simple Master Detail setup with two levels of Master Detail. The example is kept short (few rows and columns) so as to focus on the nesting.
Example Copy Link
import {
createApp,
defineComponent,
onBeforeMount,
ref,
shallowRef,
} from "vue";
import { AgGridVue } from "ag-grid-vue3";
import {
ClientSideRowModelModule,
ColDef,
ColGroupDef,
GridApi,
GridOptions,
GridReadyEvent,
IDetailCellRendererParams,
ModuleRegistry,
enableDevValidations,
} from "ag-grid-community";
import {
ColumnMenuModule,
ColumnsToolPanelModule,
ContextMenuModule,
MasterDetailModule,
} from "ag-grid-enterprise";
if (process.env.NODE_ENV !== "production") {
// Enable extended validations only for development
enableDevValidations();
}
ModuleRegistry.registerModules([
ClientSideRowModelModule,
ColumnsToolPanelModule,
MasterDetailModule,
ColumnMenuModule,
ContextMenuModule,
]);
const VueExample = defineComponent({
template: `
<div style="height: 100%">
<ag-grid-vue
style="width: 100%; height: 100%;"
@grid-ready="onGridReady"
:rowData="rowData"
:columnDefs="columnDefs"
:defaultColDef="defaultColDef"
:groupDefaultExpanded="groupDefaultExpanded"
:masterDetail="true"
:detailCellRendererParams="detailCellRendererParams"></ag-grid-vue>
</div>
`,
components: {
"ag-grid-vue": AgGridVue,
},
setup(props) {
const gridApi = shallowRef<GridApi | null>(null);
const rowData = ref<any[] | null>([
{
a1: "level 1 - 111",
b1: "level 1 - 222",
children: [
{
a2: "level 2 - 333",
b2: "level 2 - 444",
children: [
{ a3: "level 3 - 5551", b3: "level 3 - 6661" },
{ a3: "level 3 - 5552", b3: "level 3 - 6662" },
{ a3: "level 3 - 5553", b3: "level 3 - 6663" },
{ a3: "level 3 - 5554", b3: "level 3 - 6664" },
{ a3: "level 3 - 5555", b3: "level 3 - 6665" },
{ a3: "level 3 - 5556", b3: "level 3 - 6666" },
],
},
],
},
{
a1: "level 1 - 111",
b1: "level 1 - 222",
children: [
{
a2: "level 2 - 333",
b2: "level 2 - 444",
children: [
{ a3: "level 3 - 5551", b3: "level 3 - 6661" },
{ a3: "level 3 - 5552", b3: "level 3 - 6662" },
{ a3: "level 3 - 5553", b3: "level 3 - 6663" },
{ a3: "level 3 - 5554", b3: "level 3 - 6664" },
{ a3: "level 3 - 5555", b3: "level 3 - 6665" },
{ a3: "level 3 - 5556", b3: "level 3 - 6666" },
],
},
],
},
]);
const columnDefs = ref<ColDef[]>([
{ field: "a1", cellRenderer: "agGroupCellRenderer" },
{ field: "b1" },
]);
const defaultColDef = ref<ColDef>({
flex: 1,
});
const groupDefaultExpanded = ref(1);
const detailCellRendererParams = ref<any>({
// level 2 grid options
detailGridOptions: {
columnDefs: [
{ field: "a2", cellRenderer: "agGroupCellRenderer" },
{ field: "b2" },
],
defaultColDef: {
flex: 1,
},
groupDefaultExpanded: 1,
masterDetail: true,
detailRowHeight: 240,
detailCellRendererParams: {
// level 3 grid options
detailGridOptions: {
columnDefs: [
{ field: "a3", cellRenderer: "agGroupCellRenderer" },
{ field: "b3" },
],
defaultColDef: {
flex: 1,
},
},
getDetailRowData: (params) => {
params.successCallback(params.data.children);
},
} as IDetailCellRendererParams,
},
getDetailRowData: (params) => {
params.successCallback(params.data.children);
},
} as IDetailCellRendererParams);
const onGridReady = (params: GridReadyEvent) => {
gridApi.value = params.api;
};
return {
gridApi,
rowData,
columnDefs,
defaultColDef,
groupDefaultExpanded,
detailCellRendererParams,
onGridReady,
};
},
});
const app = createApp(VueExample);
app.mount("#app");
Example: Auto Height Copy Link
The next example is identical to the previous except all the Detail Grids have property detailRowAutoHeight=true. Notice that this removes all vertical scrolls from all the Detail Grids, leaving just the main Master Grid with a vertical scroll.
import {
createApp,
defineComponent,
onBeforeMount,
ref,
shallowRef,
} from "vue";
import { AgGridVue } from "ag-grid-vue3";
import {
ClientSideRowModelModule,
ColDef,
ColGroupDef,
GridApi,
GridOptions,
GridReadyEvent,
IDetailCellRendererParams,
ModuleRegistry,
enableDevValidations,
} from "ag-grid-community";
import {
ColumnMenuModule,
ColumnsToolPanelModule,
ContextMenuModule,
MasterDetailModule,
} from "ag-grid-enterprise";
if (process.env.NODE_ENV !== "production") {
// Enable extended validations only for development
enableDevValidations();
}
ModuleRegistry.registerModules([
ClientSideRowModelModule,
ColumnsToolPanelModule,
MasterDetailModule,
ColumnMenuModule,
ContextMenuModule,
]);
const VueExample = defineComponent({
template: `
<div style="height: 100%">
<ag-grid-vue
style="width: 100%; height: 100%;"
@grid-ready="onGridReady"
:rowData="rowData"
:columnDefs="columnDefs"
:defaultColDef="defaultColDef"
:groupDefaultExpanded="groupDefaultExpanded"
:masterDetail="true"
:detailRowAutoHeight="true"
:detailCellRendererParams="detailCellRendererParams"></ag-grid-vue>
</div>
`,
components: {
"ag-grid-vue": AgGridVue,
},
setup(props) {
const gridApi = shallowRef<GridApi | null>(null);
const rowData = ref<any[] | null>([
{
a1: "level 1 - 111",
b1: "level 1 - 222",
children: [
{
a2: "level 2 - 333",
b2: "level 2 - 444",
children: [
{ a3: "level 3 - 5551", b3: "level 3 - 6661" },
{ a3: "level 3 - 5552", b3: "level 3 - 6662" },
{ a3: "level 3 - 5553", b3: "level 3 - 6663" },
{ a3: "level 3 - 5554", b3: "level 3 - 6664" },
{ a3: "level 3 - 5555", b3: "level 3 - 6665" },
{ a3: "level 3 - 5556", b3: "level 3 - 6666" },
],
},
],
},
{
a1: "level 1 - 111",
b1: "level 1 - 222",
children: [
{
a2: "level 2 - 333",
b2: "level 2 - 444",
children: [
{ a3: "level 3 - 5551", b3: "level 3 - 6661" },
{ a3: "level 3 - 5552", b3: "level 3 - 6662" },
{ a3: "level 3 - 5553", b3: "level 3 - 6663" },
{ a3: "level 3 - 5554", b3: "level 3 - 6664" },
{ a3: "level 3 - 5555", b3: "level 3 - 6665" },
{ a3: "level 3 - 5556", b3: "level 3 - 6666" },
],
},
],
},
]);
const columnDefs = ref<ColDef[]>([
{ field: "a1", cellRenderer: "agGroupCellRenderer" },
{ field: "b1" },
]);
const defaultColDef = ref<ColDef>({
flex: 1,
});
const groupDefaultExpanded = ref(1);
const detailCellRendererParams = ref<any>({
// level 2 grid options
detailGridOptions: {
columnDefs: [
{ field: "a2", cellRenderer: "agGroupCellRenderer" },
{ field: "b2" },
],
defaultColDef: {
flex: 1,
},
groupDefaultExpanded: 1,
masterDetail: true,
detailRowHeight: 240,
detailRowAutoHeight: true,
detailCellRendererParams: {
// level 3 grid options
detailGridOptions: {
columnDefs: [
{ field: "a3", cellRenderer: "agGroupCellRenderer" },
{ field: "b3" },
],
defaultColDef: {
flex: 1,
},
},
getDetailRowData: (params) => {
params.successCallback(params.data.children);
},
} as IDetailCellRendererParams,
},
getDetailRowData: (params) => {
params.successCallback(params.data.children);
},
} as IDetailCellRendererParams);
const onGridReady = (params: GridReadyEvent) => {
gridApi.value = params.api;
};
return {
gridApi,
rowData,
columnDefs,
defaultColDef,
groupDefaultExpanded,
detailCellRendererParams,
onGridReady,
};
},
});
const app = createApp(VueExample);
app.mount("#app");