Beyond the Prompt A one-day AG Grid & Bryntum conference • 19th May 26 Learn more




Core Features

Advanced Features

Vue Data GridSSRM Row Grouping

Enterprise

This section covers Row Grouping in the Server-Side Row Model (SSRM).

Enabling Row Grouping Copy Link

Row Grouping is enabled in the grid via the rowGroup column definition attribute. The example below shows how to group rows by 'country':

<ag-grid-vue
    :columnDefs="columnDefs"
    /* other grid options ... */>
</ag-grid-vue>

this.columnDefs = [
    { field: 'country', rowGroup: true },
    { field: 'sport' },
    { field: 'year' },
];

For more configuration details see the section on Row Grouping.

Server Side Row Grouping Copy Link

The actual grouping of rows is performed on the server when using the SSRM. When the grid needs more rows it makes a request via getRows(params) on the Server-Side Datasource with metadata containing grouping details.

The properties relevant to Row Grouping in the request are shown below:

type IServerSideGetRowsRequest = {
    // row group columns
    rowGroupCols: ColumnVO[];

    // what groups the user is viewing
    groupKeys: string[];

    // ... // other params
}

Note in the snippet above the property rowGroupCols contains all the columns (dimensions) the grid is grouping on, e.g. 'Country', 'Year'. The property groupKeys contains the list of group keys selected, e.g. ['Argentina', '2012'].

The example below demonstrates server-side Row Grouping. Note the following:

  • Country and Sport columns have rowGroup=true defined on their column definitions. This tells the grid there are two levels of grouping, one for Country and one for Sport.
  • The rowGroupCols and groupKeys properties in the request are used by the server to perform grouping.
  • Open the browser's dev console to view the request supplied to the datasource.

Open by Default Copy Link

It is possible to have rows open as soon as they are loaded. To do this implement the grid callback isServerSideGroupOpenByDefault.

isServerSideGroupOpenByDefaultCopy Link
IsServerSideGroupOpenByDefault
Allows groups to be open by default.
// Example implementation
function isServerSideGroupOpenByDefault(params) {
    var rowNode = params.rowNode;
    var isZimbabwe = rowNode.field == 'country' && rowNode.key == 'Zimbabwe';
    return isZimbabwe;
}

Server-Side Open By Default requires Row IDs to be supplied to the grid.

It may also be helpful to use the Row Node API getRoute() to inspect the route of a row node.

getRouteCopy Link
Function
Returns the route of the row node. If the Row Node does not have a key (i.e it's a leaf row inside a row group) returns undefined

Below shows isServerSideGroupOpenByDefault() and getRoute in action. Note the following:

  • The callback opens the following routes as soon as those routes are loaded:
    • [Zimbabwe]
    • [Zimbabwe, Swimming]
    • [United States, Swimming]
  • Note [Zimbabwe] and [Zimbabwe, Swimming] are visibly open by default.
  • Note [United States, Swimming] is not visibly open by default, as the parent group 'United States' is not open. However when 'United States' is opened, it's 'Swimming' group is opened by default.
  • Selecting a group row and clicking 'Route of Selected' prints the route to the selected node to the developer console.

Group Total Rows Copy Link

To enable Group Total Rows, set the groupTotalRow property to 'top' or 'bottom'.

Group total rows can also be used with groupDisplayType='multipleColumns', as demonstrated in the example below.

Grand Total Row Copy Link

To display a grand total row, set the grandTotalRow property to 'top', 'bottom', 'pinnedTop', or 'pinnedBottom'. The grand total row is supported for both flat grids and grids with row grouping.

Providing Grand Total Data Copy Link

When grandTotalRow is set, the needsGrandTotal hint on getRows params will be true for root-level requests that don't yet have cached grand total data — this happens on first load and after any filter or aggregation change that purges the cached data. The server may also always provide updated grand total data regardless of this hint. Sort changes do not invalidate the grand total (sorting does not affect the totals), so needsGrandTotal remains false after a sort-only change.

The grandTotalData field on the success callback params controls the grand total row:

  • Pass the grand total data object to set or update the grand total row.
  • Pass null to explicitly remove an existing grand total row.
  • Leave it undefined (or omit the field entirely) to keep the grand total unchanged — the grid will continue to show whatever grand total is already cached. This lets paged block requests return data rows without having to re-send the grand total every time.

The example below shows a grouped grid with aggregations on the medal columns. Note how the grand total is recomputed server-side when filters change (reflecting the filtered totals), and that changing an aggregation function via the column menu triggers a fresh request for both data and grand total:

Alternatively, if getRowId is configured, a row with ID GRAND_TOTAL_ROW_ID ('rowGroupFooter_ROOT_NODE_ID') included in rowData will also be treated as the grand total (the grandTotalData field takes priority).

Updating the Grand Total Row via Transactions Copy Link

The grand total row can be updated, added, or removed via applyServerSideTransaction:

  • Update: Include the grand total data in the update array. The getRowId must return GRAND_TOTAL_ROW_ID ('rowGroupFooter_ROOT_NODE_ID') for this row.
  • Add: Include the grand total data in the add array. If a grand total already exists, it will be updated.
  • Remove: Include a row whose getRowId returns GRAND_TOTAL_ROW_ID ('rowGroupFooter_ROOT_NODE_ID') in the remove array to remove it.

This is useful when the grand total comes from a different endpoint than the paged data — for example, when computing totals is more expensive than loading rows and should be done in a separate, independently cancellable request.

The example below demonstrates that pattern on a flat grid. Each getRows call fetches only the data rows; whenever the grid signals needsGrandTotal, a separate asynchronous request for the grand total is started in parallel. While it is in flight the current grand total is removed via transaction so stale values aren't shown, and when the response arrives the new total is applied via an add transaction. A monotonic request id ensures that if a newer grand-total fetch is started before an earlier one returns, the stale response is discarded rather than overwriting fresher data.

Accessing Grand Total and Group Total Rows Copy Link

Both the grand total and individual group total rows can be retrieved by ID using api.getRowNode(). Two constants, exported from ag-grid-community, define the ID format:

  • GRAND_TOTAL_ROW_ID ('rowGroupFooter_ROOT_NODE_ID') — the ID of the grand total row.
  • GROUP_TOTAL_ROW_ID_PREFIX ('rowGroupFooter_') — the prefix for group total row IDs. A group total row ID is GROUP_TOTAL_ROW_ID_PREFIX + groupRowNode.id.
// Retrieve the grand total row node
const grandTotalNode = api.getRowNode(GRAND_TOTAL_ROW_ID);

// Retrieve a group total row node (e.g. for group "Ireland")
const groupTotalNode = api.getRowNode(GROUP_TOTAL_ROW_ID_PREFIX + groupRowNode.id);

Grand Total Row API Reference Copy Link

grandTotalRowCopy Link
'top' | 'bottom' | 'pinnedTop' | 'pinnedBottom'
When provided, an extra grand total row will be inserted into the grid at the specified position. This row displays the aggregate totals of all rows in the grid.

Hide Open Parents Copy Link

In some configurations it may be desired for the group row to be hidden when expanded, this can be achieved by setting the groupHideOpenParents property to true.

The example below has been styled in a way that demonstrates the behaviour of the groups. Note how upon expanding a group, the group row is replaced by the first of its children, and only when collapsed is the group row is shown again.

When groupHideOpenParents=true the Grid automatically disables the Sticky Groups behaviour of the rows as well as Full Width Loading.

Unbalanced Groups Copy Link

To enable unbalanced groups in the SSRM, set the groupAllowUnbalanced property to true. This causes any group with a key of '' to behave as if it is always expanded, and the group row to always be hidden.

When using groupAllowUnbalanced=true it is important to remember that a row group still exists to contain the unbalanced nodes, this can be an important consideration when working with selection state, refreshing, or group paths. This also means that there will be additional requests and delays in loading these unbalanced rows, as they do not belong to the parent row.

Expand All / Collapse All Copy Link

Group rows can be expanded or collapsed using the expandAll() and collapseAll() grid API's. By default, these operations apply only to loaded group rows (not all groups). To expand/collapse all groups, including those not yet loaded, set ssrmExpandAllAffectsAllRows: true in your grid options.

The example below demonstrates this feature, note the following:

  • First button expands all loaded group rows
  • Checking the checkbox enables ssrmExpandAllAffectsAllRows in the grid options
  • Now clicking the first button expands all group rows, including those not yet loaded
  • Second button collapses all group rows

To open only specific groups, e.g. only groups at the top level, then use the forEachNode() callback and open / close the row using setExpanded() as follows:

// Expand all top level row nodes
this.gridApi.forEachNode(node => {
    if (node.group && node.level == 0) {
        node.setExpanded(true);
    }
});

The example below demonstrates these techniques. Note the following:

  • Clicking 'Expand All' expands all loaded group rows. Doing this when the grid initially loads expands all Year groups. Clicking it a second time (after Year groups have loaded) causes all Year groups as well as their children Country groups to be expanded - this is a heavier operation with 100's of rows to expand.

  • Clicking 'Collapse All' collapses all rows.

  • Clicking 'Expand Top Level Only' expands Years only, even if more group rows are loaded.

Providing Child Counts Copy Link

By default, the grid does not show row counts beside the group names. If you do want row counts, you need to implement the getChildCount(dataItem) callback for the grid. The callback provides you with the row data; it is your application's responsibility to know what the child row count is. The suggestion is you set this information into the row data item you provide to the grid.

getChildCountCopy Link
GetChildCount
Allows setting the child count for a group row.
<ag-grid-vue
    :getChildCount="getChildCount"
    /* other grid options ... */>
</ag-grid-vue>

this.getChildCount = data => {
    // here child count is stored in the 'childCount' property
    return data.childCount;
};

Group via Value Getter Copy Link

It is possible the data provided has composite objects, in which case it's more difficult for the grid to extract group names. This can be worked with using value getters or embedded fields (i.e. the field attribute has dot notation).

In the example below, all rows are modified so that the rows look something like this:

// sample contents of row data
const rowData = {
    // country field is complex object
    country: {
        name: 'Ireland',
        code: 'IRE'
    },

    // other fields as normal
    ...
}

Then the columns are set up so that country uses a valueGetter that uses the field with dot notation, i.e. data.country.name

Filters Copy Link

By default, changing filters fully purges the grid. Though, it can be configured to only refresh when the group has been directly impacted by enabling serverSideOnlyRefreshFilteredGroups. Be aware, this can mean your grid may have empty group rows. This is because the grid does not refresh the groups above the groups it deems impacted by the filter.

In the example below, note the following:

  • Filtering by Gold, Silver or Bronze fully purges the grid, this is because they have aggregations applied.
  • Applying a filter to the Year column does not purge the entire grid, and instead only refreshes the Year group rows.
  • The example enables serverSideOnlyRefreshFilteredGroups, note that if you apply a filter to Year with the value 1900, no leaf rows exist in any group.

Batching Data Requests Copy Link

You can configure the Columns Tool Panel to stage changes and require an explicit Apply action before they are committed. This allows multiple configuration changes to be made and applied in a single update, avoiding unnecessary intermediate recomputations or requests.

Deferred Updates are enabled by including the Apply button in toolPanelParams.buttons.

Note that in the example below:

  • Changes made in the Columns Tool Panel are staged as pending changes.
  • Apply commits all pending changes in a single operation.
  • Cancel discards all pending changes and restores the last applied state.
<ag-grid-vue
    :sideBar="sideBar"
    /* other grid options ... */>
</ag-grid-vue>

this.sideBar = {
    toolPanels: [
        {
            id: 'columns',
            labelDefault: 'Columns',
            labelKey: 'columns',
            iconKey: 'columns',
            toolPanel: 'agColumnsToolPanel',
            toolPanelParams: {
                buttons: ['cancel', 'apply'],
            },
        },
    ],
    defaultToolPanel: 'columns',
};

Changes made outside the Columns Tool Panel — such as dragging columns into the Row Group or Pivot Panels, using the Column Menu, or calling the Grid / Column API — are applied immediately and clear any pending changes. Column pinning, resizing, and group expansion do not clear pending changes.