今天來在工作事項資料表元件上加入分頁與排序功能。
相較於我們在使用 ng add
命令產生 Table 元件時,Schematics 把分頁元件實體放至資料來源,我比較傾向單純在資料來源記錄每頁筆數與當前頁碼,來降低資料處理與介面操作之間的耦合。
export class TaskDataSource extends DataSource<TaskItem> {
readonly pageIndex = signal(0);
readonly pageSize = signal(10);
readonly totalCount = signal(0);
...
}
因此,在引用 MatPaginatorModule
之後,就可以利用 <mat-paginator>
標籤使用分頁元件。如下面程式,在分頁元件中將 length
、pageSize
與 pageIndex
等參數設定與資料來源的屬性連結。另外,我們可以透過 pageSizeOptions
來讓使用者選擇不同的每頁筆數,如果想關閉這個功能則可以設定 hidePageSize
為 true
。
<mat-paginator
[length]="dataSource.totalCount()"
[pageIndex]="dataSource.pageIndex()"
[pageSize]="dataSource.pageSize()"
[pageSizeOptions]="[5, 10, 25, 100]"
showFirstLastButtons="true"
(page)="onPageChange($event)"
/>
當使用者切換每頁筆數或是點選上下頁時,就可以利用 page
事件來取得新增資訊。
onPageChange({ pageIndex, pageSize }: PageEvent): void {
this.dataSource.pageIndex.set(pageIndex);
this.dataSource.pageSize.set(pageSize);
}
其他屬性的部分,Paginator 元件只提供上下頁的按鈕,也可以設定 showFirstLastButton
屬性來開啟第一頁與最後一頁的按鈕,但若要使用顯示每一個頁碼的需求,就只能自行開發了。
從上面可看到,Paginator 元件的預設的語系會是英文,如果希望使用其他語系或是修正元件的文字,可以建立一類別來實作 MatPaginatorIntl
介面。
@Injectable()
export class CustomPaginatorIntl implements MatPaginatorIntl {
changes = new Subject<void>();
firstPageLabel = '第一頁';
itemsPerPageLabel = '每頁筆數';
lastPageLabel = '最後一頁';
nextPageLabel = '下一頁';
previousPageLabel = '上一頁';
getRangeLabel(page: number, pageSize: number, length: number): string {
if (length === 0) {
return '第 1 頁 / 共 1 頁';
}
const amountPages = Math.ceil(length / pageSize);
return `第 ${page + 1} 頁 / 共 ${amountPages} 頁`;
}
}
接著,就可以在 app.config
來抽換 MatPaginatorIntl
提供者的實作。
export const appConfig: ApplicationConfig = {
providers: [
...
{ provide: MatPaginatorIntl, useClass: CustomPaginatorIntl },
],
};
Angular Material 把排序的實作獨立出來,在引用 MatSortModule
模組後,我們可以在一般的資料表中使用 matSort
與 mat-sort-header
指令元件。
<table matSort (matSortChange)="sortData($event)">
<tr>
<th>編號</th>
<th mat-sort-header="subject">主旨</th>
<th>內容</th>
</tr>
...
</table>
如上面程式,在一般表格中使用 mat-sort-header
會指定要排序的對象;然而,如果使用在 MatTable 之中,則會以 matColumnDef
的設定為主。
<table
mat-table
[dataSource]="dataSource"
aria-label="Elements"
matSort
(matSortChange)="onSortChange($event)"
>
<ng-container matColumnDef="subject">
<th mat-header-cell *matHeaderCellDef mat-sort-header>主旨</th>
<td mat-cell *matCellDef="let row">{{ row.subject }}</td>
<td mat-footer-cell *matFooterCellDef="">主旨表尾</td>
</ng-container>
...
</table>
當使用者選擇要排序的欄位時,就可以利用 matSortChange
事件,把排序資訊設定到資料來源內,以觸發後續的資料重整。
今天完成以資料表方式來呈現工作事項的清單,接下來我們使用卡片來呈現工作事項。