web-dev-qa-db-ja.com

Angular Material mat-table Row Grouping

特定のテーブルにrow groupingを提供するライブラリを別にして、 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>

行のグループ化にアプローチする方法についてのアイデアはありますか?

10
Vlad Danila

非常に簡単な答えは、GroupIDでソートすることです。これにより、これらの行がグループにまとめられます。ただし、各グループの前にヘッダー行を表示する必要があると思います。

Where句を使用する代替<mat-row *matRowDef="...を提供できます。これを使用して、デフォルト以外の列セットを表示できます。 where節は、そのmatRowDefを使用する必要がある場合に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列と追加の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 単にグループ化したい列のリストを提供し、それはあなたのためにグループ行を挿入します。グループ行をクリックして展開または縮小することもできます

そして最後に、マテリアルコードベースからMatTableDataSourceクラスのコピーを変更する Githubプロジェクト があります。フィルターとソートではうまく機能しますが、ページネーターとは「競合」します。両方ともレコードの表示がさまざまな方法で制限されるためです。

23
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>

グループの行を非表示にして表示することは、新しく非表示になったグループ条件に基づいて表示データをフィルタリングし、表示データを更新するだけです。

解決策を探している人々と再利用可能なコードを共有することのみを目的としたこのスレッドネクロについては申し訳ありません。