You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular 5 Material框架下表格分组、分页、排序UI插件求推荐

Solutions for Grouped, Paginated & Sortable Tables in Angular 5 + Material

Absolutely! I’ve built grouped, paginated, and sortable tables in Angular 4/5 with Material before, so I can share a few solid approaches that worked for me:

1. Extend Angular Material's Built-in Components

Since you’re already using Material, extending MatTable, MatSort, and MatPaginator is the most seamless approach. You’ll just need to add custom grouping logic.

Step 1: Prepare Grouped Data in Your Component

First, transform your raw data into grouped structures, then flatten it with group headers to feed into MatTable:

import { Component, OnInit, ViewChild } from '@angular/core';
import { MatSort, MatTableDataSource, MatPaginator } from '@angular/material';

interface Product {
  category: string;
  name: string;
  price: number;
}

@Component({
  selector: 'app-grouped-material-table',
  templateUrl: './grouped-material-table.component.html'
})
export class GroupedMaterialTableComponent implements OnInit {
  displayedColumns = ['name', 'price'];
  dataSource = new MatTableDataSource<any>();
  groupedData: { [key: string]: Product[] } = {};
  groupKeys: string[] = [];

  @ViewChild(MatSort) sort: MatSort;
  @ViewChild(MatPaginator) paginator: MatPaginator;

  ngOnInit() {
    // Sample raw data
    const rawProducts: Product[] = [
      { category: 'Electronics', name: 'Phone', price: 699 },
      { category: 'Electronics', name: 'Laptop', price: 1299 },
      { category: 'Clothing', name: 'T-Shirt', price: 29 },
      { category: 'Clothing', name: 'Jeans', price: 59 }
    ];

    // Group data by category
    this.groupedData = rawProducts.reduce((groups, product) => {
      const group = groups[product.category] || [];
      group.push(product);
      groups[product.category] = group;
      return groups;
    }, {} as { [key: string]: Product[] });
    this.groupKeys = Object.keys(this.groupedData);

    // Flatten data with group headers
    this.updateTableData();
  }

  ngAfterViewInit() {
    this.sort.sortChange.subscribe(() => this.updateTableData());
    this.dataSource.paginator = this.paginator;
  }

  private updateTableData() {
    // Sort groups and their items based on active sort
    const sortedGroups = this.groupKeys.sort();
    const sortedFlatData = sortedGroups.flatMap(key => [
      { isGroup: true, category: key, name: '', price: 0 },
      ...this.groupedData[key].sort((a, b) => {
        const isAsc = this.sort.direction === 'asc';
        switch (this.sort.active) {
          case 'name': return compare(a.name, b.name, isAsc);
          case 'price': return compare(a.price, b.price, isAsc);
          default: return 0;
        }
      })
    ]);
    this.dataSource.data = sortedFlatData;
  }
}

// Helper for sorting
function compare(a: number | string, b: number | string, isAsc: boolean) {
  return (a < b ? -1 : 1) * (isAsc ? 1 : -1);
}

Step 2: Template with Group Headers

Use *ngIf to render group headers spanning all columns, and regular rows for data:

<div class="mat-elevation-z8">
  <mat-table [dataSource]="dataSource" matSort>
    <!-- Group Header Column -->
    <ng-container matColumnDef="category">
      <mat-cell *matCellDef="let item" [attr.colspan]="displayedColumns.length" 
                class="group-header" *ngIf="item.isGroup">
        {{ item.category }}
      </mat-cell>
    </ng-container>

    <!-- Name Column -->
    <ng-container matColumnDef="name">
      <mat-header-cell *matHeaderCellDef mat-sort-header>Product Name</mat-header-cell>
      <mat-cell *matCellDef="let item" *ngIf="!item.isGroup">{{ item.name }}</mat-cell>
    </ng-container>

    <!-- Price Column -->
    <ng-container matColumnDef="price">
      <mat-header-cell *matHeaderCellDef mat-sort-header>Price ($)</mat-header-cell>
      <mat-cell *matCellDef="let item" *ngIf="!item.isGroup">{{ item.price }}</mat-cell>
    </ng-container>

    <mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
    <mat-row *matRowDef="let row; columns: ['category']" *ngIf="row.isGroup"></mat-row>
    <mat-row *matRowDef="let row; columns: displayedColumns" *ngIf="!row.isGroup"></mat-row>
  </mat-table>

  <mat-paginator [pageSizeOptions]="[5, 10, 20]" showFirstLastButtons></mat-paginator>
</div>

Note on Pagination

To avoid splitting group headers from their items, you’ll need to adjust the paginator logic. One approach is to calculate how many complete groups fit per page, or filter the flat data to ensure groups stay intact during pagination.

2. Use a Third-Party Library (ngx-datatable)

If you don’t want to build custom logic, @swimlane/ngx-datatable (version 11.x works with Angular 5) has built-in support for grouping, pagination, and sorting.

Setup & Example

  1. Install the compatible version:
npm install @swimlane/ngx-datatable@11.3.2 --save
  1. Component Implementation:
import { Component } from '@angular/core';

interface Product {
  category: string;
  name: string;
  price: number;
}

@Component({
  selector: 'app-ngx-datatable-example',
  template: `
    <ngx-datatable
      class="material"
      [rows]="products"
      [columnMode]="'force'"
      [headerHeight]="50"
      [rowHeight]="'auto'"
      [groupHeaderHeight]="50"
      [groupExpansionDefault]="true"
      [pagination]="true"
      [sortable]="true"
      [sortType]="'single'"
    >
      <ngx-datatable-column name="Product Name" prop="name"></ngx-datatable-column>
      <ngx-datatable-column name="Price ($)" prop="price"></ngx-datatable-column>
    </ngx-datatable>
  `,
  styles: [`
    ngx-datatable {
      margin: 20px;
    }
  `]
})
export class NgxDatatableExampleComponent {
  products: Product[] = [
    { category: 'Electronics', name: 'Phone', price: 699 },
    { category: 'Electronics', name: 'Laptop', price: 1299 },
    { category: 'Clothing', name: 'T-Shirt', price: 29 },
    { category: 'Clothing', name: 'Jeans', price: 59 }
  ];

  ngOnInit() {
    // Sort data by category to enable grouping
    this.products = this.products.sort((a, b) => a.category.localeCompare(b.category));
  }
}

This library handles all grouping, sorting, and pagination out of the box—great for saving time.

3. Custom Wrapper Component

If you need full control over the UI/UX, build a custom wrapper around Material’s table components. You can create a reusable GroupedTableComponent that accepts grouped data, column definitions, and handles sort/pagination internally.

Key Tips for Success

  • Version Compatibility: Ensure your Angular Material version matches Angular 5 (v5.x).
  • Performance: For large datasets, use MatTable’s virtual scrolling (cdk-virtual-scroll-viewport) to avoid rendering all rows at once.
  • Group Pagination: When implementing pagination, write a custom pipe or service to split grouped data into pages without breaking group integrity.

内容的提问来源于stack exchange,提问作者Ameya

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 08:17:53