【问题标题】:Angular Material mat-table Row GroupingAngular Material mat-table 行分组
【发布时间】:2018-09-07 07:12:47
【问题描述】:

撇开为其特定表提供行分组的库不谈,我正在尝试在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


【解决方案1】:

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

您可以提供使用 where 子句的替代 &lt;mat-row *matRowDef="...。这可用于显示一组非默认列。如果应该使用 matRowDef,where 子句采用一个返回 true 的函数。

然后,您提供给表的数据将是散布在组行中的数据行,并且该函数可以相互区分。以Basic use of &lt;table mat-table&gt;为首发,手动添加分组,在app/table-basic-example.ts中添加where子句功能:

    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 列和额外的 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 project,它修改了材料代码库中的 MatTableDataSource 类的副本。与过滤器和排序配合得很好,但与分页器“竞争”,因为它们都以不同的方式限制记录的视图。

【讨论】:

  • 使用你的代码,如何只显示某个组,例如首字母以'H'开头的组?
  • 我考虑过过滤,它可以工作,但我想在应用打开时默认只显示某个过滤组。基本上我想对数据源对象进行子集化。知道如何去做吗?
  • 嗨@guru,这是一个非常不同的话题。您应该发布一个带有一些示例代码的新问题以获得答案。
  • @StephenTurner 我想按日期过滤。但是后端日期的类型是字符串。即使将其转换为日期类型,我也会得到相同日期的不同行。如何将相同的日期组合在一起组
【解决方案2】:

使用斯蒂芬特纳的答案,现在分享这个stackblitz fork that

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

正如之前在这个帖子中指出的那样,

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

可以为每个新组开始时添加的这些行提供自定义模板 与@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>

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

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

【讨论】:

  • 你能把你的答案更多地放在上下文中吗?显示一些代码数据等
  • 感谢您的回答,我从之前链接的 stackblitz 中添加了标记示例。
  • 巨大的工作。我已经能够重用它,在每个组行上添加可累积的数字数据。不怕说这是杰作,伙计:)非常感谢
  • 感谢您的解决方案。这适用于 Angular CLI 8 吗?
  • 在我的情况下将 > 更改为 并且它有效。
【解决方案3】:

您甚至可以通过像这样解析编译和分组过程来进一步分解它:

  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) 分组只是意识到参考值不再是恒定的。这是一种蛮力方法,但基本上是分组逻辑所需要的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-06-19
    • 2019-10-10
    • 2020-02-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-05
    • 2018-03-26
    相关资源
    最近更新 更多