角度材质垫表行分组

问题描述 投票:0回答:3

抛开为特定表格提供行分组的库,我正在尝试在Angular Material 2 mat-table上实现这样的功能,但它不具备这样的功能。

填充表格的项目:

export class BasketItem{
    public id: number;
    public position: number;
    public quantity: number;
    public groupId: number;
} 

对下表中具有相同 groupId 属性的行进行分组

 <mat-table class="mat-elevation-z8" [dataSource]="dataSource" multiTemplateDataRows matSort matSortActive="position" matSortDirection="asc" matSortDisableClear >

      <!-- Position Column -->  
      <ng-container matColumnDef="position">
        <mat-header-cell *matHeaderCellDef mat-sort-header>
          <b>Position</b>
        </mat-header-cell>
        <mat-cell *matCellDef="let basketItem">{{basketItem.position}}</mat-cell>
      </ng-container>

      <!-- Quantity Column -->
      <ng-container matColumnDef="quantity">
        <mat-header-cell *matHeaderCellDef>
          <b>Quantity</b>
        </mat-header-cell>
         <mat-cell *matCellDef="let basketItem">{{basketItem.quantity}}</mat-cell>
      </ng-container>

      <!-- GroupId Column -->  
      <ng-container matColumnDef="position">
        <mat-header-cell *matHeaderCellDef mat-sort-header>
          <b>GroupId </b>
        </mat-header-cell>
        <mat-cell *matCellDef="let basketItem">{{basketItem.GroupId }}</mat-cell>
      </ng-container>


      <mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>

      <mat-row *matRowDef="let basketItem; columns: displayedColumns;" (click)="onSelect(basketItem)"></mat-row>

    </mat-table>

关于如何实现行分组有什么想法吗?

angular angular-material row grouping
3个回答
52
投票

一个非常简单的答案是按 GroupID 排序,这会将这些行分组在一起。但是,我猜您希望在每个组之前显示标题行。

您可以提供使用 where 子句的替代方案

<mat-row *matRowDef="...
。这可用于显示一组非默认列。如果应使用 matRowDef,则 where 子句采用返回 true 的函数。

您提供给表的数据将是散布在组行中的数据行,并且该函数可以区分其中一个。以 <table mat-table>

 的基本使用为开始,手动添加组并将 where 子句函数添加到 app/table-basic-example.ts:

import {Component} from '@angular/core'; export interface PeriodicElement { name: string; position: number; weight: number; symbol: string; } export interface Group { group: string; } const ELEMENT_DATA: (PeriodicElement | Group)[] = [ {group: "Group 1"}, {position: 1, name: 'Hydrogen', weight: 1.0079, symbol: 'H'}, {position: 2, name: 'Helium', weight: 4.0026, symbol: 'He'}, {position: 3, name: 'Lithium', weight: 6.941, symbol: 'Li'}, {position: 4, name: 'Beryllium', weight: 9.0122, symbol: 'Be'}, {group: "Group 2"}, {position: 5, name: 'Boron', weight: 10.811, symbol: 'B'}, {position: 6, name: 'Carbon', weight: 12.0107, symbol: 'C'}, {position: 7, name: 'Nitrogen', weight: 14.0067, symbol: 'N'}, {group: "Group 3"}, {position: 8, name: 'Oxygen', weight: 15.9994, symbol: 'O'}, {position: 9, name: 'Fluorine', weight: 18.9984, symbol: 'F'}, {position: 10, name: 'Neon', weight: 20.1797, symbol: 'Ne'}, ]; /** * @title Basic use of `<table mat-table>` */ @Component({ selector: 'table-basic-example', styleUrls: ['table-basic-example.css'], templateUrl: 'table-basic-example.html', }) export class TableBasicExample { displayedColumns: string[] = ['position', 'name', 'weight', 'symbol']; dataSource = ELEMENT_DATA; isGroup(index, item): boolean{ return item.group; } } /** Copyright 2018 Google Inc. All Rights Reserved. Use of this source code is governed by an MIT-style license that can be found in the LICENSE file at http://angular.io/license */
并将 groupHeader Column 和额外的 matRowDef 添加到 app/table-basic-example.html 中:

<mat-table [dataSource]="dataSource" class="mat-elevation-z8"> <!--- Note that these columns can be defined in any order. The actual rendered columns are set as a property on the row definition" --> <!-- Position Column --> <ng-container matColumnDef="position"> <mat-header-cell *matHeaderCellDef> No. </mat-header-cell> <mat-cell *matCellDef="let element"> {{element.position}} </mat-cell> </ng-container> <!-- Name Column --> <ng-container matColumnDef="name"> <mat-header-cell *matHeaderCellDef> Name </mat-header-cell> <mat-cell *matCellDef="let element"> {{element.name}} </mat-cell> </ng-container> <!-- Weight Column --> <ng-container matColumnDef="weight"> <mat-header-cell *matHeaderCellDef> Weight </mat-header-cell> <mat-cell *matCellDef="let element"> {{element.weight}} </mat-cell> </ng-container> <!-- Symbol Column --> <ng-container matColumnDef="symbol"> <mat-header-cell *matHeaderCellDef> Symbol </mat-header-cell> <mat-cell *matCellDef="let element"> {{element.symbol}} </mat-cell> </ng-container> <ng-container matColumnDef="groupHeader"> <mat-cell *matCellDef="let group">{{group.group}}</mat-cell> </ng-container> <mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row> <mat-row *matRowDef="let row; columns: displayedColumns"></mat-row> <mat-row *matRowDef="let row; columns: ['groupHeader']; when: isGroup"> </mat-row> </mat-table> <!-- Copyright 2018 Google Inc. All Rights Reserved. Use of this source code is governed by an MIT-style license that can be found in the LICENSE file at http://angular.io/license -->
这是一个完成的 

stackblitz,它按元素的首字母分组。

这是一个更发达的

stackblitz,只需提供您想要分组的列列表,它就会为您插入组行。您还可以单击组行来展开或折叠它们

最后这是一个

Github 项目,它修改了材料代码库中的 MatTableDataSource 类的副本。与过滤器和排序配合得很好,但与分页器“竞争”,因为它们都以不同的方式限制记录的视图。


20
投票
使用 Stephen Turner 的答案,现在分享这个

stackblitz fork that

    动态发现给定数据中的列
  • 允许根据需要按列的不同值进行分组

正如本主题前面指出的那样,

使用 Mat-Table 进行 groupBy 的简单方法实际上是在显示的数据中添加行,

可以为每个新组开始时添加的这些行提供自定义模板 与 @Input(matRowDefWhen)

<!-- Default Table lines --> <tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: true"></tr> <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr> <!-- Group line --> <tr mat-row *matRowDef="let row; columns: ['groupName']; when: isAGroup"></tr>

在上面的示例中,当一行是一个组而不是初始数据的一部分时,isAGroup 函数应返回 true。

groupName 列模板也可以按如下方式实现

<ng-container matColumnDef="groupName"> <td colspan="999" mat-cell *matCellDef="let group"> {{group.name}} </td> </ng-container>

最后,如果您的数据集可以变化,可以在列模板定义上添加循环

<ng-container *ngFor="let col of displayedColumns" [matColumnDef]="col"> <th mat-header-cell *matHeaderCellDef>{{ col }}</th> <td mat-cell *matCellDef="let row">{{ row[col] }}</td> </ng-container>

然后隐藏和显示组的行只是根据新隐藏的组标准过滤显示的数据并刷新显示的数据。

抱歉这个线程死灵,只是为了向那些寻找解决方案的人分享一段可重用的代码。


0
投票
您甚至可以通过解析编译和分组过程来进一步分解它,如下所示:

sortStringArray(array: string[], sortOrder: string = 'asc'): string[] { if(sortOrder === 'asc'){ array.sort((a: string, b: string) => a > b ? 1 : a < b ? -1 : 0); } else if(sortOrder === 'desc'){ array.sort((a: string, b: string) => a > b ? -1 : a < b ? 1 : 0); } return array; } groupStringArray(array: string[], sortOrder: string = 'asc'): string[] { let sortedArray = this.sortStringArray(array, sortOrder); let groupHeader = ''; let groupedArray = []; for(let i = 0; i < sortedArray.length; i++){ if(groupHeader !== sortedArray[i]){ groupHeader = sortedArray[i]; groupedArray.push({ isGroup: true, value: groupHeader }); groupedArray.push(sortedArray[i]); } else{ groupedArray.push(sortedArray[i]); } } return groupedArray; }
...并对您正在处理的每种不同类型的值以及您期望与字段一起返回的值执行此操作。这是更具可读性和单一责任的地方,您可以在其他地方应用这些函数,并在表的分组中轻松实现它们。我已经将我的设置设置为处理所有类型,甚至以这种干净的可读性递归工作。当您 1) 意识到排序首先可以更轻松地查找和设置分组值,2) 分组只是意识到参考值不再恒定时,问题就更容易解决。这是一种蛮力方法,但它基本上是分组逻辑所需要的。

© www.soinside.com 2019 - 2024. All rights reserved.