Type to search columns, filters, options, and extensions.

to navigate · Enter to open · Esc to close

Documentation

Row Group Extension

Group related rows and add per-group summaries

When To Use

Use Row Group when a table is easier to scan when related rows are displayed together, such as employees by department or orders by customer. The extension groups the rows shown on the current page; it does not aggregate the complete server-side result set.

Basic Grouping

The grouping source is required. Use a property name for object rows or a column index for array rows.

use Pentiminax\UX\DataTables\Model\DataTableExtensions;
use Pentiminax\UX\DataTables\Model\Extensions\RowGroupExtension;

public function configureExtensions(DataTableExtensions $extensions): DataTableExtensions
{
    return $extensions->addExtension(
        new RowGroupExtension(dataSrc: 'department')
    );
}

Group rows should be ordered by the same data source so that each group remains contiguous. When the grouping source is a column, apply an initial order for that column in configureDataTable().

Multi-level Grouping

Pass a list ordered from the outermost group to the innermost group:

new RowGroupExtension(dataSrc: ['department', 'office']);

Configuration Options

new RowGroupExtension(
    dataSrc: 'department',
    enable: false,
    className: 'table-group',
    startClassName: 'table-group-start',
    endClassName: 'table-group-end',
    emptyDataGroup: 'Unassigned',
);

With the default renderer, setting emptyDataGroup to null omits the grouping row for null, undefined, or empty grouping values. Row Group still collects those data rows into a group internally. If you configure startRender or endRender, return null for the missing group value to keep its grouping row hidden. Setting enable to false loads Row Group but leaves it initially disabled for later activation through the DataTables API.

Custom JavaScript Grouping And Summaries

PHP configuration is serialized as JSON, so dataSrc, startRender, and endRender functions must be attached through the datatables:pre-connect event.

this.element.addEventListener('datatables:pre-connect', (event) => {
  const config = event.detail.config.rowGroup

  config.dataSrc = (rowData) => (rowData.salary < 50000 ? 'Under 50,000' : '50,000 and above')

  config.startRender = (rows, group) => {
    if (group === null || group === '') {
      return null
    }

    const row = document.createElement('tr')
    const cell = document.createElement('td')

    cell.colSpan = event.detail.config.columns.length
    cell.textContent = `${group} (${rows.count()} rows)`
    row.append(cell)

    return row
  }

  config.endRender = (rows, group) =>
    group === null || group === '' ? null : `Visible rows in this group: ${rows.count()}`
})

Use DOM nodes and textContent when group values can contain user-provided data. Returning an HTML string requires the application to escape every untrusted value. Render callbacks run again after paging, searching, and ordering, so keep them synchronous and inexpensive. Set either renderer to null when its grouping row should not be displayed.

Ajax And Server-side Tables

Every returned row must contain the property selected by dataSrc. A grouping property may be provided by a hidden column:

yield TextColumn::new('department', 'Department')->setVisible(false);

When overriding mapRow(), keep the grouping property in the returned array even when it is not displayed. Row Group only sees the current Ajax page, so counts and other summaries calculated in a render callback are page-level values rather than totals for the full filtered result set.

Compatibility

  • Row Group is not compatible with Scroller.
  • Buttons exports omit grouping rows and export only the underlying data rows.
  • Expanding or collapsing groups is not provided by Row Group.

These combinations are documented but are not blocked by UX DataTables at runtime.