iT邦幫忙

2024 iThome 鐵人賽

DAY 5
0
Modern Web

用 Angular Material 開發應用程式系列 第 5

Day 5 - 資料表清單

  • 分享至 

  • xImage
  •  

今天來利用 Angular Material 的 Table 元件,建立工作事項的資料表清單元件。

新增 Table 元件

在使用 Angular Material 的時候,可以利用 Angular Schemaics 來建立如表格、樹狀元件等 Material 元件。

ng generate @angular/material:table task-table

因此,透過上面指令來建立工作事項的資料表後,可以看到 Schemaics 除了建立元件的檔案外,也新增了一個 DataSource 的程式碼,這是 Material 實作資料清單的基本架構。

https://ithelp.ithome.com.tw/upload/images/20240919/20109645L3rlCMOwkJ.png

Table 的資料來源

Data Source 的定義可以把清單的介面與資料拆分處理,無論靜態的資料陣列或是動態的 Observable 都可以當作資料來源。

在 Schemaics 所產生的程式碼裡,會幫我們定義一個讓資料表使用項目介面,我們可以依需求來修正所使用的資料對象。另外,為了讓資料來源可以完成獨立於介面,我會刪除 Schemaics 在 DataSource 所使用到的 paginatorsort 元件實體參數。

export class TaskDataSource extends DataSource<TaskItem> {
  connect(): Observable<TaskItem[]> {}
  disconnect(): void {}
}

如上面程式中,資料來源來繼承 @angular/cdk/collection 裡的 DataSource 類別,我們需要去定義此類別的 connect()disconnect() 兩個方法,前者會回傳一 Observable 型別資料,讓我們定義當某些資料更改時,需要重新取得資料的邏輯;後者則是讓元件被銷毀時,所需要的作業邏輯。

export class TaskDataSource extends DataSource<TaskItem> {
  readonly tasks = signal<TaskItem[]>([]);
  private readonly tasks$ = toObservable(this.tasks);
  
  constructor(tasks: TaskItem[]) {
    super();
    this.tasks.set(tasks);
  }

  connect(): Observable<TaskItem[]> {
    return this.tasks$;
  }
}

我們可以如上面程式,以靜態陣列資料作為資料來源;也可以在建立資料來源實體時,傳入對應的資料服務實體,透過與後端取得所需要的資料。

export class TaskDataSource extends DataSource<TaskItem> {
  constructor(private readonly tasksService: TaskService) {
    super();
  }

  connect(): Observable<TaskItem[]> {
    return this.tasksService.getList();
  }
}

Table 的欄位定義

在引用 MatTableModule 模組之後,就可以使用 <mat-table> 標籤,或是在 <table> 裡加入 mat-table 指令元件,並指定資料表的資料來源。

<table mat-table [dataSource]="dataSource" aria-label="Elements">
</table>

Angular Material Table 把資料表結構拆分成欄位定義以及資料表頭、表身與表尾定義兩個部分。首先,如下面程式,會利用 matColumnDef 來定義資料欄位,其中 mat-header-cellmatHeaderCellDef 用以定義欄位標題,而 mat-cellmatCellDef 則是定義欄位內容。

<ng-container matColumnDef="id">
  <th mat-header-cell *matHeaderCellDef>編號</th>
  <td mat-cell *matCellDef="let row">{{ row.id }}</td>
</ng-container>

上面程式只定義此資料表會有哪些資料欄位,真正會顯示的欄位定義則會在 <tr> 中使用 mat-header-rowmat-row 進行設定。當我們需要變更欄位顯示或是順序,都可以透過操控 displayedColumns 這個屬性值來實現。

<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns"></tr>

https://ithelp.ithome.com.tw/upload/images/20240919/20109645evhGMukUj1.png

Table 的表頭與表尾列定義

Material 的 Table 元件允許設定多列的表頭列、內容列與表尾列。如下面程式,除了在欄位使用 mat-footer-cellmatFooterCellDef 定義各欄位的頁尾內容。

<ng-container matColumnDef="id">
  <th mat-header-cell *matHeaderCellDef>編號</th>
  <td mat-cell *matCellDef="let row">{{ row.id }}</td>
  <td mat-footer-cell *matFooterCellDef></td>
</ng-container>

或是如下面程式,針對所需要的表首與表尾欄位單獨定義。

<ng-container matColumnDef="subject-desc">
  <th mat-header-cell *matHeaderCellDef>工作事項主旨</th>
</ng-container>

<ng-container matColumnDef="content-desc">
  <th mat-header-cell *matHeaderCellDef>工作事項詳細說明</th>
</ng-container>

<ng-container matColumnDef="total">
  <td mat-footer-cell *matFooterCellDef colspan="3">共 18 筆工作事項</td>
</ng-container>

最後,在利用 mat-header-rowmat-footer-row 定義在表首與表尾實際需要顯示的欄位。

<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr
  mat-header-row
  *matHeaderRowDef="['id-desc', 'subject-desc', 'content-desc']"
></tr>

<tr mat-row *matRowDef="let row; columns: displayedColumns"></tr>

<tr mat-footer-row *matFooterRowDef="displayedColumns"></tr>
<tr mat-footer-row *matFooterRowDef="['total']"></tr>

https://ithelp.ithome.com.tw/upload/images/20240919/20109645f5tZ79RkCr.png

順帶一提,我們可以在欄位定義時,利用 stickystickyEnd 屬性來設定此欄位是否被固定在左邊或是右邊。

<ng-container matColumnDef="id" sticky="true">
  <th mat-header-cell *matHeaderCellDef>編號</th>
  <td mat-cell *matCellDef="let row">{{ row.id }}</td>
  <td mat-footer-cell *matFooterCellDef></td>
</ng-container>

同樣的,可以在表頭與表尾的設定上使用 sticky 屬性來固定表頭或表尾的顯示。

  <tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: true"></tr>

今日範例

接下來

明天我們在今天所建立的工作事項資料表元件中加入分頁與排序的需求。


上一篇
Day 4 - 圖示與側邊欄
下一篇
Day 6 - 分頁與排序
系列文
用 Angular Material 開發應用程式30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言