みんなのちからになりたい

コピペでブログラムつくっていきたい

MatTableのSortなにもわからない

Angular独特すぎていつまで経ってもよくわからないし、さらに輪をかけてAngular Materialもよくわからない

デザインが変わるからTailwindみたいなCSSフレームワークと同じ感覚で使ってしまっていてわけわからんって感じになっていて、そうじゃないと理解できると意味わかるという感じ

そういうCSSフレームワーク的な理解でMatTableにソート付けたくて難儀したってことをメモしていきたい

ソート付けるためには

Table | Angular Material

テーブルにソート動作を追加するには、 matSort ディレクティブをテーブルに追加し、ソートをトリガする各列ヘッダセルに mat-sort-header を追加します。 matSort ディレクティブを初期化するには、MatSortModule をインポートする必要があることに注意してください (API ドキュメントを参照してください)。

こういうこと

<table matSort (matSortChange)="sortData($event)">
  <tr>
    <th mat-sort-header="name">Dessert (100g)</th>
    <th mat-sort-header="calories">Calories</th>
    <th mat-sort-header="fat">Fat (g)</th>
    <th mat-sort-header="carbs">Carbs (g)</th>
    <th mat-sort-header="protein">Protein (g)</th>
  </tr>

やってみた

matSortやsort-header付けただけだと画面上なんの変更もない

MatSortModuleをimportすると矢印がつく(もちろんソートはされない)

テーブルのデータソースに MatTableDataSource を使用している場合、データソースに MatSort ディレクティブを指定すると、ソートの変更を自動的にリッスンし、テーブルによってレンダリングされるデータの順序を変更します。

デフォルトでは、MatTableDataSource は、ソートされた列の名前が、列が表示するデータ・プロパティ名と一致することを前提としてソートします。 例えば、以下の列定義は position という名前で、行セルに表示されるプロパティの名前と一致します。

MatTableDataSourceとはなにか

Table | Angular Material

DataSourceを拡張したもので、クライアント側のデータ配列を受け入れ,フィルタリング,(MatSort を用いた)ソート,(MatPaginator を用いた)ページ分割をネイティブにサポートするデータソース

sortingDataAccessor をオーバーライドすることで、 ソートのカスタマイズが可能になります。 また、filterPredicate をオーバーライドすることで、 フィルタのカスタマイズも可能になります。これは、フィルタマッチのために行データをどのように文字列に変換するかを定義します。

注意: このクラスは使い始めるためのシンプルなデータソースです。 そのため、堅牢な国際化サポートやサーバーサイドのインタラクションのような、より高度なケースを扱うための機能は備えていません。 あなたのアプリがより高度な使用例をサポートする必要がある場合は、独自のDataSourceを実装することを検討してください。

要は、MatTableDataSourceにすると自動的にソートとかフィルタとかなにもしなくても実装してくれてるってこと?

やってみた

してくれるが、かなりクセがある

以下ソートのドキュメント Table | Angular Material

まず、 @ViewChild(MatSort) sort: MatSort;これをやらないとソートしてくれない

こいつの説明が何もなく唐突にサンプルに出てくる

4oくんに聞いてみた


MatSortは、Angular Materialのソート機能を提供するためのディレクティブです。MatTableと組み合わせて使用することで、ユーザーがテーブルの列ヘッダーをクリックすることで、その列に基づいてテーブルのデータをソートできるようにします。

基本的な使い方

  1. HTMLのセットアップ: テーブルの各列ヘッダーにmat-sort-headerディレクティブを追加します。これにより、ソート機能が有効になります。
   <table mat-table [dataSource]="dataSource" matSort>
     <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>
     <!-- 他の列も同様に定義 -->
   </table>
  1. コンポーネントでのセットアップ: @ViewChildデコレーターを使って、MatSortインスタンスを取得し、それをデータソースに関連付けます。これにより、テーブルデータが自動的にソートされるようになります。
   import { Component, ViewChild } from '@angular/core';
   import { MatSort } from '@angular/material/sort';
   import { MatTableDataSource } from '@angular/material/table';

   @Component({
     selector: 'app-my-table',
     templateUrl: './my-table.component.html',
   })
   export class MyTableComponent {
     displayedColumns: string[] = ['name', 'age', 'address'];
     dataSource = new MatTableDataSource(ELEMENT_DATA);

     @ViewChild(MatSort) sort: MatSort;

     ngAfterViewInit() {
       this.dataSource.sort = this.sort;
     }
   }

### @ViewChildについて

  • @ViewChild(MatSort) sort: MatSort;は、AngularのViewChildデコレーターを使って、MatSortディレクティブのインスタンスを取得しています。
  • @ViewChildは、Angularがテンプレート内の特定のコンポーネントやディレクティブへの参照をコンポーネントクラスに注入するための機能です。この場合、MatSortディレクティブのインスタンスsortというプロパティに割り当てられます。
  • ngAfterViewInitライフサイクルフックでthis.dataSource.sort = this.sort;を設定することで、テーブルデータがMatSortと連携して動作するようになります。

なぜ@ViewChildが必要なのか

@ViewChildを使用する理由は、MatSortはテンプレート内に宣言されているため、コンポーネントクラス内で直接参照できないからです。@ViewChildを使うことで、テンプレートに存在するMatSortディレクティブをクラス内で操作できるようになります。

まとめ

MatSortを使用するためには、HTMLでmat-sort-headerを各列ヘッダーに追加し、コンポーネントクラスで@ViewChildを使ってMatSortを取得し、データソースに関連付ける必要があります。このプロセスにより、テーブル内のデータを簡単にソートできるようになります。

参考ページ: Angular Material Sort Overview


↑ テンプレに設定してるMatSort direvtiveにアクセスするためにViewChildがいるってことらしい

direvtiveってテンプレでしか使ったことなくて、directiveのメソッドにアクセスしてなんかしたいってことなかったから考えもしなかったど、こういうケースで使えるってことなのか、これはすごい勉強になる


this.dataSource.sort = this.sort;これをすることでソートされる


ここまでやってやっと気づいたのが、mat-tableとかこいつらディレクティブでコンポーネントでもなんでもないってことで、これ付けたらCSSが変わって見た目が変わるって理解しかしてなかったけど(まあそうなんだけど)、ディレクティブだから内部でよろしくやって見た目変えてたんだなと

これが理解できたらたしかに公式にちゃんと書いてあるわ…って感じであって、理解って大事だなと思いました