AngularMaterialのTableで任意の値(松竹梅など)をSortする方法


はじめに

Angular Material のTableコンポーネントでSortするときに、単純な数値や文字列の順序ではなく、独自のステータス(松竹梅など)でSortする方法をまとめます。
※ Angular MaterialはGoogleが提唱しているMaterial Designに準拠したAngular用のUIコンポーネント集です。

基本となるテーブル

まず、基本的なSortに対応したテーブルを作成します。

  • sample-table.component.html
<table mat-table [dataSource]="dataSource" matSort class="mat-elevation-z8">
  <!-- no Column -->
  <ng-container matColumnDef="no">
    <th mat-header-cell *matHeaderCellDef mat-sort-header> No. </th>
    <td mat-cell *matCellDef="let element"> {{element.no}} </td>
  </ng-container>

  <!-- Name Column -->
  <ng-container matColumnDef="name">
    <th mat-header-cell *matHeaderCellDef mat-sort-header> Name </th>
    <td mat-cell *matCellDef="let element"> {{element.name}} </td>
  </ng-container>

  <!-- course Column -->
  <ng-container matColumnDef="course">
    <th mat-header-cell *matHeaderCellDef mat-sort-header> Course </th>
    <td mat-cell *matCellDef="let element"> {{element.course}} </td>
  </ng-container>

  <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
  <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
  • sample-table.component.ts
export interface Reservation {
  no: number;
  name: string;
  course: string;
}

const SAMPLE_DATA: Reservation[] = [
  {no: 0, name: "佐藤", course: ""},
  {no: 1, name: "鈴木", course: ""},
  {no: 2, name: "高橋", course: ""},
  {no: 3, name: "田中", course: ""},
  {no: 4, name: "伊藤", course: ""},
  {no: 5, name: "渡辺", course: ""},
  {no: 6, name: "山本", course: ""},
  {no: 7, name: "中村", course: ""},
  {no: 8, name: "小林", course: ""},
  {no: 9, name: "加藤", course: ""},
  {no: 10, name: "吉田", course: ""},
  {no: 11, name: "山田", course: ""},
  {no: 12, name: "佐々木", course: ""},
];

@Component({
  selector: 'sample-table',
  styleUrls: ['sample-table.component.css'],
  templateUrl: 'sample-table.component.html',
})
export class SampleTableComponent implements OnInit {
  displayedColumns: string[] = ['no', 'name', 'course'];
  dataSource = new MatTableDataSource(SAMPLE_DATA);

  @ViewChild(MatSort, {static: true}) sort: MatSort;

  ngOnInit() {
    this.dataSource.sort = this.sort;
  }
}
  • sample-table.component.css
table {
  width: 100%;
}

th.mat-sort-header-sorted {
  color: black;
}

ちなみに、この段階で、courseで昇順にすると、松→梅→竹になります。
これを松→竹→梅になるように対応します。

Sort順序のカスタマイズ

Sort順序のカスタマイズにはMatTableDataSourcesortingDataAccessorを利用します。
sortingDataAccessorの型定義は下記の通りです。

(data: T, sortHeaderId: string) => string | number

dataはSAMPLE_DATAの1行分のデータが入ります。そのため、この関数は行数分コールされます。
sortHeaderIdはSort対象のidが入ります。(courseカラムのSortを実行した場合は"course")

Sort順序をカスタマイズするには、下記のようにsortingDataAccessorへ関数を代入します。

  • sample-table.component.ts
ngOnInit() {
  this.dataSource.sort = this.sort;
  this.dataSource.sortingDataAccessor = (item, property) => {
    if (property == "course") {
      switch (item.course) {
        case "":
          return 0;
        case "":
          return 1;
        case "":
          return 2;
        default:
          return 3;
      }
    }
    return (item as any)[property];
  };
}

まず、if (property == "course")でcourseカラムのSortのときだけ動作するようにします。それ以外はreturn (item as any)[property];でデフォルト動作になるようにしています。
if文の中では松竹梅に合わせてnumber型を返します。これにより、任意の値のSort順序を制御できます。