Angular Material (Components Cdk) 學習筆記 Table

refer : git

https://material.angular.io/cdk/table/overviewgithub

https://material.angular.io/components/table/overview數據庫

 

一般咱們作 control panel 時會大量運用到 table api

尤爲是處理 CRUD 時, table 更是神器架構

說到 table 就必定會附帶如下這些東西 框架

filter, search ide

paginationui

sortthis

show/hide/sort columnsspa

select row

cell display 

Table 做爲高複用組件, 必需要足夠抽象。

material 在這裏也是一如往常的作出了數據和 ui 分離. 

這個概念和 angular directive form 是同樣的. 

數據方面的處理是交給 DataSource 這個對象來負責. 

這個對象監聽 filter, search, sort 等等數據的變更,而後對數據進行處理 (mat table data source 目前沒有支持遠程數據處理, 咱們得本身實現)

而後 ui table 經過監聽 data source 來獲取新數據. 

各類小組件, mat-sort, mat-pagination 則是負責監聽 ui 操做.

因此是

data source 監聽操做小組件 -> 更新 source 

ui table 監聽 data source -> 渲染

這個就是大體上架構的設計啦,咱們只能跟着作了

 

 

下面說說經常使用的東西. 

1. ui table

首先開一個"家「 監聽 data source 

<table mat-table [dataSource]="dataSource" [trackBy]="trackByFn" >
</table>

而後是裏面

<ng-container matColumnDef="cost">
  <th mat-header-cell *matHeaderCellDef> Cost </th>
  <td mat-cell *matCellDef="let data"> {{data.cost}} </td>
  <td mat-footer-cell *matFooterCellDef> {{totalCost}} </td>
</ng-container>

...

<tr mat-header-row *matHeaderRowDef="columnsToDisplay"></tr>
<tr mat-row *matRowDef="let myRowData; columns: columnsToDisplay"></tr>
<tr mat-footer-row *matFooterRowDef="columnsToDisplay"></tr>

定義每個 column template

一個 column 又分爲 3 個 template 展示,  header,body,footer

最後 3 行則是定義 row 的呈現. 

不是每個 column 都有 3 個展示的, 有些只有 header, body, 有些則只有 footer, 沒有就不要定義就行了

row 的 columnsToDisplay 也不是所有同樣的, 有一些 columns 只須要展示在 footer, 那麼它就只出如今 row footer 的 columnsToDisplay 就行了。

 

 

 

2. max-text-column, 這個就是一個方便啦. 由於大部分都是 display string 嘛.

<mat-text-column name="score"></mat-text-column>

源碼是很簡單的

@Component({
  moduleId: module.id,
  selector: 'mat-text-column',
  template: `
    <ng-container matColumnDef>
      <th mat-header-cell *matHeaderCellDef [style.text-align]="justify">
        {{headerText}}
      </th>
      <td mat-cell *matCellDef="let data" [style.text-align]="justify">
        {{dataAccessor(data, name)}}
      </td>
    </ng-container>
  `,
  encapsulation: ViewEncapsulation.None, 
  changeDetection: ChangeDetectionStrategy.Default,
})
export class MatTextColumn<T> extends CdkTextColumn<T> {
}

經過 CdkTextColumn @input 去修改 header or cell, 

@Input() headerText: string;
@Input() dataAccessor: (data: T, name: string) => string;

 

3. Paginator 

這個就是上面說的操做小組件啦, 

  <mat-paginator #matPaginator [pageSizeOptions]="[1, 10, 20]"></mat-paginator>

經過 #matPaginator 打標籤, 而後 controller 就能夠用 ViewChild 找到它 

@ViewChild('matPaginator', { read: MatPaginator, static: false })
matPaginator: MatPaginator;

這裏我用 static false,大部分狀況 true 是 ok 的, 不熟悉的人能夠看看 angular 8.0 瞭解一下.

ngAfterViewInit() {
  this.dataSource.paginator = this.matPaginator;
}

而後就是讓它與 data source 關聯, 這樣 data source 就會監聽這個小組件了. 每一次 ui 換 page, data source 就能過去換數據了. 

注意: dataSource.paginator 是一個 getter setter 屬性來的, 因此即便咱們在 AfterViewInit 才 set, ui table 同樣會渲染. 

源碼 : 

  get paginator(): MatPaginator | null { return this._paginator; }
  set paginator(paginator: MatPaginator|null) {
    this._paginator = paginator;
    this._updateChangeSubscription(); // ui table 監聽到這個就會 render 了咯
  }
  private _paginator: MatPaginator|null;

 

 

4. Sort 

和上面溝通差很少, 在 table 打上 matSort 指令和 #matSort, 這裏要對準 matSort 的 exportAs 哦 

題外話標籤對上指令就要對準 exportAs, 標籤 defualt 是拿 element 和 component 的

  <table mat-table [dataSource]="dataSource" [trackBy]="trackByFn" matSort #matSort="matSort" >

而後咱們在咱們想 sort 的 header 加上 mat-sort-header 指令

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

不是每個 column 都是能夠 sort 的嘛, 固然須要表態一下咯, 

看出來, matSort 基本上只是爲了溝通而誕生的.

@ViewChild('matSort', { read: MatSort, static: false })
matSort: MatSort;


ngAfterViewInit() {
  this.dataSource.paginator = this.matPaginator;
  this.dataSource.sort = this.matSort;
}

 

5. filter search 

這個我就很少說了, 

 this.dataSource.filter = 'string here'; 

它也是 setter 因此每次值改變了它都會跑 

 

自定義 data source 

上面說了 material data source 只能處理 local 數據. 可是真實項目裏咱們的數據大部分是 backend 來的,要經過 api 去拿才行. 

我本身使用了 odata 因此對於作 dynamic table 來講仍是比較輕鬆的. 

咱們沿着 material 的思路走, 同樣使用 material 提供的操做小組件 sort, paginator 只是本身實現 data source 就好. 

因此這裏咱們主要看看怎樣讓它們溝通. 

Paginator 

this.matPaginator.length = 1000;
this.matPaginator.pageIndex = 0; // 注意 0 是開始, 而不是 1
this.matPaginator.page.subscribe((e: PageEvent) => {
  // pageIndex 或 pageSize 變化時觸發
  console.log(e.length);
  console.log(e.pageIndex);
  console.log(e.pageSize);
  console.log(e.previousPageIndex);
});

當 data source 獲取到資料後, 就能夠 set length 了 (這個 length 是說數據庫裏有多少, 而不是拿下來了多少哦)

若是是 filter update 了, 一般 pageIndex 都會 set to start, 因此這個接口會用到. 

當咱們 set pageIndex 和 length 時, 是不會觸發 PageEvent 事件的哦。它會去同步 view 而已.

最後就是監聽用戶的操做了. 

 

 

 

 

 

 

 

 

 

說說目前 material 的缺失. 

1. loading and data not found 

這麼基本的功能都沒有.... 

https://github.com/angular/components/issues/8661

workaround : 放 loading 和 not found 放到 table 下面. 沒有 footer 的狀況下, 看不出來. 有 footer 本身保重

 

2. column resize 

https://github.com/angular/components/issues/8312

這個也是很基本的功能,也是沒有, 

work aound: 本身能夠勉強實現啦... 不過...

 

3. drag and drop row 

這個也是基本功能, 本身實現也是很累的...

https://github.com/angular/components/issues/13770

 

4. visual scroll 

這個不僅是 table, 全部 material 能用到 visual scroll 的大部分都沒有 build in 的實現

甚至說,很難去實現... 

https://github.com/angular/components/issues/10122

 

最後吐槽一下, 不僅是 material, angular 還有不少不少的功能都不齊全. 

只有用的人才知道它的侷限有多大. 固然個人意思不是說其它框架有實現. 

只是做爲一個大而全的框架,我對待它的要求就是.... 我只想寫業務邏輯相關的代碼..... 哈哈哈

預計 angular 10 或 11 以後就會很不錯了. 

相關文章
相關標籤/搜索