This section shows how the detail height can be customised to suit application requirements.
Detail Height Options Copy Link
The default height of each detail section (ie the row containing the Detail Grid in the master) is fixed at 300px. The height does not change based on how much data there is to display in the detail section.
To change the height of the details section from the default you have the following options:
Fixed Height: a custom fixed height can be provided for all detail sections instead of the default
300px.Auto Height: detail sections can auto-size to fit based off the contents.
Dynamic Height: different heights can be provided for each detail section.
Fixed Height Copy Link
Use the grid property detailRowHeight to set a fixed height for each detail row.
const gridOptions = {
// statically fix row height for all detail grids
detailRowHeight: 200,
// other grid options ...
}The following example sets a fixed row height for all detail rows.
import {
ClientSideRowModelModule,
FirstDataRenderedEvent,
GridApi,
GridOptions,
IDetailCellRendererParams,
ModuleRegistry,
RowApiModule,
createGrid,
enableDevValidations,
} from "ag-grid-community";
import {
ColumnMenuModule,
ColumnsToolPanelModule,
ContextMenuModule,
MasterDetailModule,
} from "ag-grid-enterprise";
import { IAccount, ICallRecord } from "./interfaces";
if (process.env.NODE_ENV !== "production") {
// Enable extended validations only for development
enableDevValidations();
}
ModuleRegistry.registerModules([
RowApiModule,
ClientSideRowModelModule,
ColumnsToolPanelModule,
MasterDetailModule,
ColumnMenuModule,
ContextMenuModule,
]);
let gridApi: GridApi<IAccount>;
const gridOptions: GridOptions<IAccount> = {
columnDefs: [
// group cell renderer needed for expand / collapse icons
{ field: "name", cellRenderer: "agGroupCellRenderer" },
{ field: "account" },
{ field: "calls" },
{ field: "minutes", valueFormatter: "x.toLocaleString() + 'm'" },
],
defaultColDef: {
flex: 1,
},
masterDetail: true,
detailRowHeight: 200,
detailCellRendererParams: {
detailGridOptions: {
columnDefs: [
{ field: "callId" },
{ field: "direction" },
{ field: "number", minWidth: 150 },
{ field: "duration", valueFormatter: "x.toLocaleString() + 's'" },
{ field: "switchCode", minWidth: 150 },
],
defaultColDef: {
flex: 1,
},
},
getDetailRowData: (params) => {
params.successCallback(params.data.callRecords);
},
} as IDetailCellRendererParams<IAccount, ICallRecord>,
alwaysShowVerticalScroll: true,
onFirstDataRendered: onFirstDataRendered,
};
function onFirstDataRendered(params: FirstDataRenderedEvent) {
// arbitrarily expand a row for presentational purposes
setTimeout(() => {
params.api.getDisplayedRowAtIndex(1)!.setExpanded(true);
}, 0);
}
const gridDiv = document.querySelector<HTMLElement>("#myGrid")!;
gridApi = createGrid(gridDiv, gridOptions);
fetch("https://www.ag-grid.com/example-assets/master-detail-data.json")
.then((response) => response.json())
.then((data: IAccount[]) => {
gridApi!.setGridOption("rowData", data);
});
<div id="myGrid" style="height: 100%"></div>
export interface ICallRecord {
name: string;
callId: number;
duration: number;
switchCode: string;
direction: string;
number: string;
}
export interface IAccount {
name: string;
account: number;
calls: number;
minutes: number;
callRecords: ICallRecord[];
} Auto Height Copy Link
Set grid property detailRowAutoHeight=true to have the detail grid dynamically change its height to fit its rows.
const gridOptions = {
// dynamically set row height for all detail grids
detailRowAutoHeight: true,
// other grid options ...
}import {
ClientSideRowModelModule,
FirstDataRenderedEvent,
GridApi,
GridOptions,
IDetailCellRendererParams,
ModuleRegistry,
RowApiModule,
createGrid,
enableDevValidations,
} from "ag-grid-community";
import { MasterDetailModule } from "ag-grid-enterprise";
import { IAccount, ICallRecord } from "./interfaces";
if (process.env.NODE_ENV !== "production") {
// Enable extended validations only for development
enableDevValidations();
}
ModuleRegistry.registerModules([
RowApiModule,
ClientSideRowModelModule,
MasterDetailModule,
]);
let gridApi: GridApi<IAccount>;
const gridOptions: GridOptions<IAccount> = {
columnDefs: [
// group cell renderer needed for expand / collapse icons
{ field: "name", cellRenderer: "agGroupCellRenderer" },
{ field: "account" },
{ field: "calls" },
{ field: "minutes", valueFormatter: "x.toLocaleString() + 'm'" },
],
defaultColDef: {
flex: 1,
},
masterDetail: true,
detailRowAutoHeight: true,
detailCellRendererParams: {
detailGridOptions: {
columnDefs: [
{ field: "callId" },
{ field: "direction" },
{ field: "number", minWidth: 150 },
{ field: "duration", valueFormatter: "x.toLocaleString() + 's'" },
{ field: "switchCode", minWidth: 150 },
],
defaultColDef: {
flex: 1,
},
},
getDetailRowData: (params) => {
params.successCallback(params.data.callRecords);
},
} as IDetailCellRendererParams<IAccount, ICallRecord>,
alwaysShowVerticalScroll: true,
onFirstDataRendered: onFirstDataRendered,
};
function onFirstDataRendered(params: FirstDataRenderedEvent) {
// arbitrarily expand a row for presentational purposes
setTimeout(() => {
params.api.getDisplayedRowAtIndex(1)!.setExpanded(true);
}, 0);
}
const gridDiv = document.querySelector<HTMLElement>("#myGrid")!;
gridApi = createGrid(gridDiv, gridOptions);
fetch("https://www.ag-grid.com/example-assets/master-detail-data.json")
.then((response) => response.json())
.then((data: IAccount[]) => {
gridApi!.setGridOption("rowData", data);
});
<div id="myGrid" style="height: 100%"></div>
export interface ICallRecord {
name: string;
callId: number;
duration: number;
switchCode: string;
direction: string;
number: string;
}
export interface IAccount {
name: string;
account: number;
calls: number;
minutes: number;
callRecords: ICallRecord[];
} When using Auto Height, the Detail Grid will have a minimum height of 150px for the rows section, and no maximum height. See Minimum and Maximum Height with Auto Height for more information on how to change this.
If you do not set a maximum height when enabling Auto Height, the Detail Grid will render all of its rows all the time. Row Virtualisation will not happen. This means if the Detail Grid has many rows, it could slow down your application and could result in stalling the browser.
If you have large data sets in detail rows, say 100+ rows, ensure that you set a value for the autoHeightMaxBodyHeight theme parameter.
Auto Height with Custom Detail Copy Link
If you are providing your own Detail Cell Renderer, set detailRowAutoHeight: true in the master-level gridOptions and ensure the content nested inside the detail cell renderer component sets a height value.
Here is an example of Auto Height being used with a Custom Detail Cell Renderer:
import {
ClientSideRowModelModule,
FirstDataRenderedEvent,
GridApi,
GridOptions,
IDetailCellRendererParams,
ModuleRegistry,
RowApiModule,
createGrid,
enableDevValidations,
} from "ag-grid-community";
import { MasterDetailModule } from "ag-grid-enterprise";
import { IAccount, ICallRecord } from "./interfaces";
export class DetailCellRenderer {
eGui: HTMLDivElement | undefined;
init() {
this.eGui = document.createElement("div");
//additional content shown in detail
const panel = document.createElement("div");
// Notice: the height is set
panel.style =
"height:100px; background-color:lightblue; padding: 15px; font-weight: bold; ";
panel.innerText = "Optional element content";
// button to toggle optional content visibility
const btn = document.createElement("button");
btn.innerText = "Show Optional Element";
btn.style = "margin:10px";
btn.addEventListener("click", function (p: any) {
//add your own condition here based on application logic - this only checks the number of children shown
if (p.target.parentElement.children.length === 1) {
p.target.parentElement.appendChild(panel);
p.target.innerText = "Hide Optional Element";
} else {
p.target.parentElement.removeChild(panel);
p.target.innerText = "Show Optional Element";
}
});
this.eGui.appendChild(btn);
}
getGui() {
return this.eGui;
}
refresh() {
return false;
}
}
if (process.env.NODE_ENV !== "production") {
// Enable extended validations only for development
enableDevValidations();
}
ModuleRegistry.registerModules([
RowApiModule,
ClientSideRowModelModule,
MasterDetailModule,
]);
let gridApi: GridApi<IAccount>;
const gridOptions: GridOptions<IAccount> = {
columnDefs: [
// group cell renderer needed for expand / collapse icons
{ field: "name", cellRenderer: "agGroupCellRenderer" },
{ field: "account" },
{ field: "calls" },
{ field: "minutes", valueFormatter: "x.toLocaleString() + 'm'" },
],
defaultColDef: {
flex: 1,
},
masterDetail: true,
detailRowAutoHeight: true,
detailCellRendererParams: {
detailGridOptions: {
columnDefs: [
{ field: "callId" },
{ field: "direction" },
{ field: "number", minWidth: 150 },
{ field: "duration", valueFormatter: "x.toLocaleString() + 's'" },
{ field: "switchCode", minWidth: 150 },
],
defaultColDef: {
flex: 1,
},
},
getDetailRowData: (params) => {
params.successCallback(params.data.callRecords);
},
} as IDetailCellRendererParams<IAccount, ICallRecord>,
onFirstDataRendered: onFirstDataRendered,
detailCellRenderer: DetailCellRenderer,
};
function onFirstDataRendered(params: FirstDataRenderedEvent) {
// arbitrarily expand a row for presentational purposes
setTimeout(() => {
params.api.getDisplayedRowAtIndex(1)!.setExpanded(true);
}, 0);
}
const gridDiv = document.querySelector<HTMLElement>("#myGrid")!;
gridApi = createGrid(gridDiv, gridOptions);
fetch("https://www.ag-grid.com/example-assets/master-detail-data.json")
.then((response) => response.json())
.then((data: IAccount[]) => {
gridApi!.setGridOption("rowData", data);
});
<div id="myGrid" style="height: 100%"></div>
export interface ICallRecord {
name: string;
callId: number;
duration: number;
switchCode: string;
direction: string;
number: string;
}
export interface IAccount {
name: string;
account: number;
calls: number;
minutes: number;
callRecords: ICallRecord[];
} Dynamic Height Copy Link
Use the callback getRowHeight(params) to set height for each row individually. This is a specific use of the callback that is explained in more detail in Get Row Height
Callback version of property rowHeight to set height for each row individually. Function should return a positive number of pixels, or return null/undefined to use the default row height. |
Note that this callback gets called for all rows in the Master Grid, not just rows containing Detail Grids. If you do not want to set row heights explicitly for other rows simply return undefined / null and the grid will ignore the result for that particular row.
const gridOptions = {
// dynamically assigning detail row height
getRowHeight: params => {
const isDetailRow = params.node.detail;
// for all rows that are not detail rows, return nothing
if (!isDetailRow) { return undefined; }
// otherwise return height based on number of rows in detail grid
const detailPanelHeight = params.data.children.length * 50;
return detailPanelHeight;
},
// other grid options ...
}The following example demonstrates dynamic detail row heights:
import {
ClientSideRowModelModule,
FirstDataRenderedEvent,
GridApi,
GridOptions,
IDetailCellRendererParams,
ModuleRegistry,
RenderApiModule,
RowApiModule,
RowHeightParams,
createGrid,
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([
RenderApiModule,
RowApiModule,
ClientSideRowModelModule,
ColumnsToolPanelModule,
MasterDetailModule,
ColumnMenuModule,
ContextMenuModule,
]);
let gridApi: GridApi;
const gridOptions: GridOptions = {
columnDefs: [
// group cell renderer needed for expand / collapse icons
{ field: "name", cellRenderer: "agGroupCellRenderer" },
{ field: "account" },
{ field: "calls" },
{ field: "minutes", valueFormatter: "x.toLocaleString() + 'm'" },
],
defaultColDef: {
flex: 1,
},
masterDetail: true,
detailCellRendererParams: {
detailGridOptions: {
columnDefs: [
{ field: "callId" },
{ field: "direction" },
{ field: "number" },
{ field: "duration", valueFormatter: "x.toLocaleString() + 's'" },
{ field: "switchCode" },
],
defaultColDef: {
flex: 1,
},
onGridReady: (params) => {
// using auto height to fit the height of the the detail grid
params.api.setGridOption("domLayout", "autoHeight");
},
},
getDetailRowData: (params) => {
params.successCallback(params.data.callRecords);
},
} as IDetailCellRendererParams<IAccount, ICallRecord>,
getRowHeight: (params: RowHeightParams) => {
if (params.node && params.node.detail) {
const offset = 80;
const allDetailRowHeight =
params.data.callRecords.length *
params.api.getSizesForCurrentTheme().rowHeight;
const gridSizes = params.api.getSizesForCurrentTheme();
return (
allDetailRowHeight +
((gridSizes && gridSizes.headerHeight) || 0) +
offset
);
}
},
alwaysShowVerticalScroll: true,
onFirstDataRendered: onFirstDataRendered,
};
function onFirstDataRendered(params: FirstDataRenderedEvent) {
// arbitrarily expand a row for presentational purposes
setTimeout(() => {
params.api.getDisplayedRowAtIndex(1)!.setExpanded(true);
}, 0);
}
const gridDiv = document.querySelector<HTMLElement>("#myGrid")!;
gridApi = createGrid(gridDiv, gridOptions);
fetch(
"https://www.ag-grid.com/example-assets/master-detail-dynamic-row-height-data.json",
)
.then((response) => response.json())
.then(function (data) {
gridApi!.setGridOption("rowData", data);
});
<div id="myGrid" style="height: 100%"></div>