Grouping

Row grouping allows users to collapse rows into hierarchical groups based on column values. Click the group icon in a column header to group by that column. Grouped rows display a count of their subRows and can be expanded to show the underlying data. Use an aggregationFn on columns like "Visits" to aggregate values (e.g., sum) when rows are grouped.

Username
Account Status
Role
Avg Session Duration
Company Name
Last Visited At
Visit Count
Schuyler_Strosin-Lemke3 suspended user 111 Kris LLC 10 Jun 2024 07:18:57 PDT 177
Liza.Corwin pending user 119 Hirthe, Mertz and Olson 24 Jan 2025 05:59:43 PDT 2
Wilton.Stark23 suspended user 119 Boyer, Kutch and Koepp 26 Jul 2025 11:42:30 PDT 482
Earl.Kassulke38 pending user 106 Kreiger - Monahan 09 Aug 2025 17:04:58 PDT 83
Adonis_Feil73 active moderator 100 Lebsack and Sons 28 May 2024 09:35:14 PDT 11
General.Hansen18 active moderator 118 Weimann Group 11 Jul 2025 10:45:45 PDT 390
Drew_Barrows pending admin 101 Schuppe and Sons 14 Oct 2025 01:57:07 PDT 2
Drake.Reinger41 active moderator 114 Yundt, Reilly and Schowalter 24 Sep 2025 01:52:39 PDT 172
Jesse_Nader active admin 117 Stroman, Klein and Zboncak 26 Jul 2025 13:21:58 PDT 71
Chanelle.Morar pending moderator 110 King Group 12 Aug 2025 20:26:41 PDT 72
import {Component} from "@angular/core"
import {Combine, Ungroup} from "lucide-angular"

import {PaginationModule} from "@qualcomm-ui/angular/pagination"
import {
  type AngularTable,
  createAngularTable,
  createTablePagination,
  TableModule,
} from "@qualcomm-ui/angular/table"
import {provideIcons} from "@qualcomm-ui/angular-core/lucide"
import {
  getCoreRowModel,
  getExpandedRowModel,
  getGroupedRowModel,
  getPaginationRowModel,
} from "@qualcomm-ui/core/table"

import {createUserQuery, type User, userColumns} from "./data"

@Component({
  imports: [TableModule, PaginationModule],
  providers: [provideIcons({Combine, Ungroup})],
  selector: "grouping-demo",
  template: `
    <div q-table-root>
      <div q-table-scroll-container>
        <table q-table-table>
          <thead q-table-header>
            @for (
              headerGroup of table.getHeaderGroups();
              track headerGroup.id
            ) {
              <tr q-table-row>
                @for (header of headerGroup.headers; track header.id) {
                  <th q-table-header-cell>
                    @if (!header.isPlaceholder) {
                      <div class="flex items-center gap-1">
                        @if (header.column.getCanGroup()) {
                          <button
                            q-table-column-header-action
                            [icon]="
                              header.column.getIsGrouped()
                                ? 'Ungroup'
                                : 'Combine'
                            "
                            (click)="header.column.toggleGrouping()"
                          ></button>
                        }
                        <ng-container *renderHeader="header; let value">
                          {{ value }}
                        </ng-container>
                      </div>
                    }
                  </th>
                }
              </tr>
            }
          </thead>
          <tbody q-table-body>
            @for (row of table.getRowModel().rows; track row.id) {
              <tr q-table-row>
                @for (cell of row.getVisibleCells(); track cell.id) {
                  <td q-table-cell>
                    @if (cell.getIsGrouped()) {
                      <!-- If it's a grouped cell, add an expander and row count -->
                      <div class="inline-flex items-center gap-2">
                        @if (row.getCanExpand()) {
                          <button
                            q-table-row-expand-button
                            [isExpanded]="row.getIsExpanded()"
                            [row]="row"
                          ></button>
                        }
                      </div>
                    }
                    <ng-container
                      *renderCell="
                        cell;
                        isAggregated: cell.getIsAggregated();
                        let value
                      "
                    >
                      {{ value }}
                    </ng-container>
                  </td>
                }
              </tr>
            }
          </tbody>
        </table>
      </div>
      <div
        q-table-pagination
        [count]="pagination.count()"
        [page]="pagination.page()"
        [pageSize]="pagination.pageSize()"
        (pageChanged)="pagination.onPageChange($event)"
      >
        <div *paginationContext="let context" q-pagination-page-metadata>
          @let meta = context.pageMetadata;
          {{ meta.pageStart }}-{{ meta.pageEnd }} of {{ meta.count }} results
        </div>

        <div q-pagination-page-buttons></div>
      </div>
    </div>
  `,
})
export class GroupingDemo {
  protected readonly query = createUserQuery(1000)

  protected table: AngularTable<User> = createAngularTable(() => ({
    columns: userColumns,
    data: this.query.data() || [],
    getCoreRowModel: getCoreRowModel(),
    getExpandedRowModel: getExpandedRowModel(),
    getGroupedRowModel: this.query.data()?.length
      ? getGroupedRowModel()
      : undefined,
    getPaginationRowModel: getPaginationRowModel(),
  }))

  protected pagination = createTablePagination(this.table)
}
Last updated on by Ryan Bower